Mercurial > emacs
comparison lisp/wid-edit.el @ 17799:0df9495348e7
Synched with 1.97.
author | Per Abrahamsen <abraham@dina.kvl.dk> |
---|---|
date | Wed, 14 May 1997 17:31:13 +0000 |
parents | d6545cfb6c5a |
children | bccd356a3b7c |
comparison
equal
deleted
inserted
replaced
17798:f59c9a63514b | 17799:0df9495348e7 |
---|---|
2 ;; | 2 ;; |
3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
4 ;; | 4 ;; |
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> | 5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> |
6 ;; Keywords: extensions | 6 ;; Keywords: extensions |
7 ;; Version: 1.90 | 7 ;; Version: 1.97 |
8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ | 8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ |
9 | 9 |
10 ;; This file is part of GNU Emacs. | 10 ;; This file is part of GNU Emacs. |
11 | 11 |
12 ;; GNU Emacs is free software; you can redistribute it and/or modify | 12 ;; GNU Emacs is free software; you can redistribute it and/or modify |
63 (set-extent-property ext 'atomic t))) | 63 (set-extent-property ext 'atomic t))) |
64 (defun widget-make-intangible (from to size) | 64 (defun widget-make-intangible (from to size) |
65 "Make text between FROM and TO intangible." | 65 "Make text between FROM and TO intangible." |
66 (put-text-property from to 'intangible 'front))) | 66 (put-text-property from to 'intangible 'front))) |
67 | 67 |
68 (if (string-match "XEmacs" emacs-version) | |
69 (defun widget-event-point (event) | |
70 "Character position of the end of event if that exists, or nil." | |
71 (if (mouse-event-p event) | |
72 (event-point event) | |
73 nil)) | |
74 (defun widget-event-point (event) | |
75 "Character position of the end of event if that exists, or nil." | |
76 (posn-point (event-end event)))) | |
77 | |
68 ;; The following should go away when bundled with Emacs. | 78 ;; The following should go away when bundled with Emacs. |
69 (condition-case () | 79 (condition-case () |
70 (require 'custom) | 80 (require 'custom) |
71 (error nil)) | 81 (error nil)) |
72 | 82 |
80 (when (fboundp 'copy-face) | 90 (when (fboundp 'copy-face) |
81 (copy-face 'default 'widget-documentation-face) | 91 (copy-face 'default 'widget-documentation-face) |
82 (copy-face 'bold 'widget-button-face) | 92 (copy-face 'bold 'widget-button-face) |
83 (copy-face 'italic 'widget-field-face))) | 93 (copy-face 'italic 'widget-field-face))) |
84 | 94 |
85 (unless (fboundp 'event-point) | 95 (unless (fboundp 'button-release-event-p) |
86 ;; XEmacs function missing in Emacs. | 96 ;; XEmacs function missing from Emacs. |
87 (defun event-point (event) | 97 (defun button-release-event-p (event) |
88 "Return the character position of the given mouse-motion, button-press, | 98 "Non-nil if EVENT is a mouse-button-release event object." |
89 or button-release event. If the event did not occur over a window, or did | 99 (and (eventp event) |
90 not occur over text, then this returns nil. Otherwise, it returns an index | 100 (memq (event-basic-type event) '(mouse-1 mouse-2 mouse-3)) |
91 into the buffer visible in the event's window." | 101 (or (memq 'click (event-modifiers event)) |
92 (posn-point (event-start event)))) | 102 (memq 'drag (event-modifiers event)))))) |
93 | 103 |
94 (unless (fboundp 'error-message-string) | 104 (unless (fboundp 'error-message-string) |
95 ;; Emacs function missing in XEmacs. | 105 ;; Emacs function missing in XEmacs. |
96 (defun error-message-string (obj) | 106 (defun error-message-string (obj) |
97 "Convert an error value to an error message." | 107 "Convert an error value to an error message." |
140 (t | 150 (t |
141 (:italic t))) | 151 (:italic t))) |
142 "Face used for editable fields." | 152 "Face used for editable fields." |
143 :group 'widgets) | 153 :group 'widgets) |
144 | 154 |
145 (defcustom widget-menu-max-size 40 | |
146 "Largest number of items allowed in a popup-menu. | |
147 Larger menus are read through the minibuffer." | |
148 :group 'widgets | |
149 :type 'integer) | |
150 | |
151 ;;; Utility functions. | 155 ;;; Utility functions. |
152 ;; | 156 ;; |
153 ;; These are not really widget specific. | 157 ;; These are not really widget specific. |
154 | 158 |
155 (defsubst widget-plist-member (plist prop) | 159 (defsubst widget-plist-member (plist prop) |
176 | 180 |
177 (defun widget-clear-undo () | 181 (defun widget-clear-undo () |
178 "Clear all undo information." | 182 "Clear all undo information." |
179 (buffer-disable-undo (current-buffer)) | 183 (buffer-disable-undo (current-buffer)) |
180 (buffer-enable-undo)) | 184 (buffer-enable-undo)) |
185 | |
186 (defcustom widget-menu-max-size 40 | |
187 "Largest number of items allowed in a popup-menu. | |
188 Larger menus are read through the minibuffer." | |
189 :group 'widgets | |
190 :type 'integer) | |
181 | 191 |
182 (defun widget-choose (title items &optional event) | 192 (defun widget-choose (title items &optional event) |
183 "Choose an item from a list. | 193 "Choose an item from a list. |
184 | 194 |
185 First argument TITLE is the name of the list. | 195 First argument TITLE is the name of the list. |
223 (when (stringp try) | 233 (when (stringp try) |
224 (setq val try)) | 234 (setq val try)) |
225 (cdr (assoc val items))) | 235 (cdr (assoc val items))) |
226 nil))))) | 236 nil))))) |
227 | 237 |
228 (defun widget-get-sibling (widget) | |
229 "Get the item WIDGET is assumed to toggle. | |
230 This is only meaningful for radio buttons or checkboxes in a list." | |
231 (let* ((parent (widget-get widget :parent)) | |
232 (children (widget-get parent :children)) | |
233 child) | |
234 (catch 'child | |
235 (while children | |
236 (setq child (car children) | |
237 children (cdr children)) | |
238 (when (eq (widget-get child :button) widget) | |
239 (throw 'child child))) | |
240 nil))) | |
241 | |
242 ;;; Helper functions. | |
243 ;; | |
244 ;; These are widget specific. | |
245 | |
246 ;;;###autoload | |
247 (defun widget-prompt-value (widget prompt &optional value unbound) | |
248 "Prompt for a value matching WIDGET, using PROMPT. | |
249 The current value is assumed to be VALUE, unless UNBOUND is non-nil." | |
250 (unless (listp widget) | |
251 (setq widget (list widget))) | |
252 (setq widget (widget-convert widget)) | |
253 (let ((answer (widget-apply widget :prompt-value prompt value unbound))) | |
254 (unless (widget-apply widget :match answer) | |
255 (error "Value does not match %S type." (car widget))) | |
256 answer)) | |
257 | |
258 ;;; Widget text specifications. | 238 ;;; Widget text specifications. |
259 ;; | 239 ;; |
260 ;; These functions are for specifying text properties. | 240 ;; These functions are for specifying text properties. |
261 | 241 |
262 (defun widget-specify-none (from to) | 242 (defun widget-specify-none (from to) |
523 (defun widget-apply-action (widget &optional event) | 503 (defun widget-apply-action (widget &optional event) |
524 "Apply :action in WIDGET in response to EVENT." | 504 "Apply :action in WIDGET in response to EVENT." |
525 (if (widget-apply widget :active) | 505 (if (widget-apply widget :active) |
526 (widget-apply widget :action event) | 506 (widget-apply widget :action event) |
527 (error "Attempt to perform action on inactive widget"))) | 507 (error "Attempt to perform action on inactive widget"))) |
508 | |
509 ;;; Helper functions. | |
510 ;; | |
511 ;; These are widget specific. | |
512 | |
513 ;;;###autoload | |
514 (defun widget-prompt-value (widget prompt &optional value unbound) | |
515 "Prompt for a value matching WIDGET, using PROMPT. | |
516 The current value is assumed to be VALUE, unless UNBOUND is non-nil." | |
517 (unless (listp widget) | |
518 (setq widget (list widget))) | |
519 (setq prompt (format "[%s] %s" (widget-type widget) prompt)) | |
520 (setq widget (widget-convert widget)) | |
521 (let ((answer (widget-apply widget :prompt-value prompt value unbound))) | |
522 (unless (widget-apply widget :match answer) | |
523 (error "Value does not match %S type." (car widget))) | |
524 answer)) | |
525 | |
526 (defun widget-get-sibling (widget) | |
527 "Get the item WIDGET is assumed to toggle. | |
528 This is only meaningful for radio buttons or checkboxes in a list." | |
529 (let* ((parent (widget-get widget :parent)) | |
530 (children (widget-get parent :children)) | |
531 child) | |
532 (catch 'child | |
533 (while children | |
534 (setq child (car children) | |
535 children (cdr children)) | |
536 (when (eq (widget-get child :button) widget) | |
537 (throw 'child child))) | |
538 nil))) | |
528 | 539 |
529 ;;; Glyphs. | 540 ;;; Glyphs. |
530 | 541 |
531 (defcustom widget-glyph-directory (concat data-directory "custom/") | 542 (defcustom widget-glyph-directory (concat data-directory "custom/") |
532 "Where widget glyphs are located. | 543 "Where widget glyphs are located. |
570 (if (file-readable-p file) | 581 (if (file-readable-p file) |
571 (widget-glyph-insert-glyph widget tag (make-glyph file)) | 582 (widget-glyph-insert-glyph widget tag (make-glyph file)) |
572 ;; File not readable, give up. | 583 ;; File not readable, give up. |
573 (insert tag)))))) | 584 (insert tag)))))) |
574 | 585 |
575 (defun widget-glyph-insert-glyph (widget tag glyph) | 586 (defun widget-glyph-insert-glyph (widget tag glyph &optional down inactive) |
576 "In WIDGET, with alternative text TAG, insert GLYPH." | 587 "In WIDGET, with alternative text TAG, insert GLYPH." |
577 (set-glyph-image glyph (cons 'tty tag)) | 588 (set-glyph-image glyph (cons 'tty tag)) |
578 (set-glyph-property glyph 'widget widget) | 589 (set-glyph-property glyph 'widget widget) |
590 (when down | |
591 (set-glyph-image down (cons 'tty tag)) | |
592 (set-glyph-property down 'widget widget)) | |
593 (when inactive | |
594 (set-glyph-image inactive (cons 'tty tag)) | |
595 (set-glyph-property inactive 'widget widget)) | |
579 (insert "*") | 596 (insert "*") |
580 (add-text-properties (1- (point)) (point) | 597 (add-text-properties (1- (point)) (point) |
581 (list 'invisible t | 598 (list 'invisible t |
582 'end-glyph glyph)) | 599 'end-glyph glyph)) |
600 (widget-put widget :glyph-up glyph) | |
601 (when down (widget-put widget :glyph-down down)) | |
602 (when inactive (widget-put widget :glyph-inactive inactive)) | |
583 (let ((help-echo (widget-get widget :help-echo))) | 603 (let ((help-echo (widget-get widget :help-echo))) |
584 (when help-echo | 604 (when help-echo |
585 (let ((extent (extent-at (1- (point)) nil 'end-glyph)) | 605 (let ((extent (extent-at (1- (point)) nil 'end-glyph)) |
586 (help-property (if (featurep 'balloon-help) | 606 (help-property (if (featurep 'balloon-help) |
587 'balloon-help | 607 'balloon-help |
704 (define-key widget-keymap "\C-k" 'widget-kill-line) | 724 (define-key widget-keymap "\C-k" 'widget-kill-line) |
705 (define-key widget-keymap "\t" 'widget-forward) | 725 (define-key widget-keymap "\t" 'widget-forward) |
706 (define-key widget-keymap "\M-\t" 'widget-backward) | 726 (define-key widget-keymap "\M-\t" 'widget-backward) |
707 (define-key widget-keymap [(shift tab)] 'widget-backward) | 727 (define-key widget-keymap [(shift tab)] 'widget-backward) |
708 (define-key widget-keymap [backtab] 'widget-backward) | 728 (define-key widget-keymap [backtab] 'widget-backward) |
709 (if (string-match "XEmacs" (emacs-version)) | 729 (if (string-match "XEmacs" emacs-version) |
710 (progn | 730 (progn |
711 (define-key widget-keymap [button2] 'widget-button-click) | 731 ;;Glyph support. |
712 (define-key widget-keymap [button1] 'widget-button1-click)) | 732 (define-key widget-keymap [button1] 'widget-button1-click) |
713 (define-key widget-keymap [mouse-2] 'ignore) | 733 (define-key widget-keymap [button2] 'widget-button-click)) |
714 (define-key widget-keymap [down-mouse-2] 'widget-button-click)) | 734 (define-key widget-keymap [down-mouse-2] 'widget-button-click)) |
715 (define-key widget-keymap "\C-m" 'widget-button-press)) | 735 (define-key widget-keymap "\C-m" 'widget-button-press)) |
716 | 736 |
717 (defvar widget-global-map global-map | 737 (defvar widget-global-map global-map |
718 "Keymap used for events the widget does not handle themselves.") | 738 "Keymap used for events the widget does not handle themselves.") |
748 (if field | 768 (if field |
749 (widget-apply-action field event) | 769 (widget-apply-action field event) |
750 (call-interactively | 770 (call-interactively |
751 (lookup-key widget-global-map (this-command-keys)))))) | 771 (lookup-key widget-global-map (this-command-keys)))))) |
752 | 772 |
773 (defface widget-button-pressed-face | |
774 '((((class color)) | |
775 (:foreground "red")) | |
776 (t | |
777 (:bold t :underline t))) | |
778 "Face used for pressed buttons." | |
779 :group 'widgets) | |
780 | |
753 (defun widget-button-click (event) | 781 (defun widget-button-click (event) |
754 "Activate button below mouse pointer." | 782 "Activate button below mouse pointer." |
755 (interactive "@e") | 783 (interactive "@e") |
756 (cond ((and (fboundp 'event-glyph) | 784 (cond ((and (fboundp 'event-glyph) |
757 (event-glyph event)) | 785 (event-glyph event)) |
758 (let ((widget (glyph-property (event-glyph event) 'widget))) | 786 (widget-glyph-click event)) |
759 (if widget | 787 ((widget-event-point event) |
760 (widget-apply-action widget event) | 788 (let* ((pos (widget-event-point event)) |
761 (message "You clicked on a glyph.")))) | 789 (button (get-text-property pos 'button))) |
762 ((event-point event) | |
763 (let ((button (get-text-property (event-point event) 'button))) | |
764 (if button | 790 (if button |
765 (widget-apply-action button event) | 791 (let ((begin (previous-single-property-change (1+ pos) 'button)) |
792 (end (next-single-property-change pos 'button)) | |
793 overlay) | |
794 (unwind-protect | |
795 (let ((track-mouse t)) | |
796 (setq overlay (make-overlay begin end)) | |
797 (overlay-put overlay 'face 'widget-button-pressed-face) | |
798 (overlay-put overlay | |
799 'mouse-face 'widget-button-pressed-face) | |
800 (unless (widget-apply button :mouse-down-action event) | |
801 (while (not (button-release-event-p event)) | |
802 (setq event (if (fboundp 'read-event) | |
803 (read-event) | |
804 (next-event)) | |
805 pos (widget-event-point event)) | |
806 (if (and pos | |
807 (eq (get-text-property pos 'button) | |
808 button)) | |
809 (progn | |
810 (overlay-put overlay | |
811 'face | |
812 'widget-button-pressed-face) | |
813 (overlay-put overlay | |
814 'mouse-face | |
815 'widget-button-pressed-face)) | |
816 (overlay-put overlay 'face nil) | |
817 (overlay-put overlay 'mouse-face nil)))) | |
818 | |
819 (when (and pos | |
820 (eq (get-text-property pos 'button) button)) | |
821 (widget-apply-action button event))) | |
822 (delete-overlay overlay))) | |
766 (call-interactively | 823 (call-interactively |
767 (or (lookup-key widget-global-map [ button2 ]) | 824 (or (lookup-key widget-global-map [ button2 ]) |
768 (lookup-key widget-global-map [ down-mouse-2 ]) | 825 (lookup-key widget-global-map [ down-mouse-2 ]) |
769 (lookup-key widget-global-map [ mouse-2])))))) | 826 (lookup-key widget-global-map [ mouse-2])))))) |
770 (t | 827 (t |
773 (defun widget-button1-click (event) | 830 (defun widget-button1-click (event) |
774 "Activate glyph below mouse pointer." | 831 "Activate glyph below mouse pointer." |
775 (interactive "@e") | 832 (interactive "@e") |
776 (if (and (fboundp 'event-glyph) | 833 (if (and (fboundp 'event-glyph) |
777 (event-glyph event)) | 834 (event-glyph event)) |
835 (widget-glyph-click event) | |
836 (call-interactively (lookup-key widget-global-map (this-command-keys))))) | |
837 | |
838 (defun widget-glyph-click (event) | |
839 "Handle click on a glyph." | |
840 (let* ((glyph (event-glyph event)) | |
841 (widget (glyph-property glyph 'widget)) | |
842 (extent (event-glyph-extent event)) | |
843 (down-glyph (or (and widget (widget-get widget :glyph-down)) glyph)) | |
844 (up-glyph (or (and widget (widget-get widget :glyph-up)) glyph)) | |
845 (last event)) | |
846 ;; Wait for the release. | |
847 (while (not (button-release-event-p last)) | |
848 (if (eq extent (event-glyph-extent last)) | |
849 (set-extent-property extent 'end-glyph down-glyph) | |
850 (set-extent-property extent 'end-glyph up-glyph)) | |
851 (setq last (next-event event))) | |
852 ;; Release glyph. | |
853 (when down-glyph | |
854 (set-extent-property extent 'end-glyph up-glyph)) | |
855 ;; Apply widget action. | |
856 (when (eq extent (event-glyph-extent last)) | |
778 (let ((widget (glyph-property (event-glyph event) 'widget))) | 857 (let ((widget (glyph-property (event-glyph event) 'widget))) |
779 (if widget | 858 (cond ((null widget) |
780 (widget-apply-action widget event) | 859 (message "You clicked on a glyph.")) |
781 (message "You clicked on a glyph."))) | 860 ((not (widget-apply widget :active)) |
782 (call-interactively (lookup-key widget-global-map (this-command-keys))))) | 861 (message "This glyph is inactive.")) |
862 (t | |
863 (widget-apply-action widget event))))))) | |
783 | 864 |
784 (defun widget-button-press (pos &optional event) | 865 (defun widget-button-press (pos &optional event) |
785 "Activate button at POS." | 866 "Activate button at POS." |
786 (interactive "@d") | 867 (interactive "@d") |
787 (let ((button (get-text-property pos 'button))) | 868 (let ((button (get-text-property pos 'button))) |
1005 | 1086 |
1006 ;;; Widget Functions | 1087 ;;; Widget Functions |
1007 ;; | 1088 ;; |
1008 ;; These functions are used in the definition of multiple widgets. | 1089 ;; These functions are used in the definition of multiple widgets. |
1009 | 1090 |
1091 (defun widget-parent-action (widget &optional event) | |
1092 "Tell :parent of WIDGET to handle the :action. | |
1093 Optional EVENT is the event that triggered the action." | |
1094 (widget-apply (widget-get widget :parent) :action event)) | |
1095 | |
1010 (defun widget-children-value-delete (widget) | 1096 (defun widget-children-value-delete (widget) |
1011 "Delete all :children and :buttons in WIDGET." | 1097 "Delete all :children and :buttons in WIDGET." |
1012 (mapcar 'widget-delete (widget-get widget :children)) | 1098 (mapcar 'widget-delete (widget-get widget :children)) |
1013 (widget-put widget :children nil) | 1099 (widget-put widget :children nil) |
1014 (mapcar 'widget-delete (widget-get widget :buttons)) | 1100 (mapcar 'widget-delete (widget-get widget :buttons)) |
1015 (widget-put widget :buttons nil)) | 1101 (widget-put widget :buttons nil)) |
1016 | 1102 |
1103 (defun widget-children-validate (widget) | |
1104 "All the :children must be valid." | |
1105 (let ((children (widget-get widget :children)) | |
1106 child found) | |
1107 (while (and children (not found)) | |
1108 (setq child (car children) | |
1109 children (cdr children) | |
1110 found (widget-apply child :validate))) | |
1111 found)) | |
1112 | |
1017 (defun widget-types-convert-widget (widget) | 1113 (defun widget-types-convert-widget (widget) |
1018 "Convert :args as widget types in WIDGET." | 1114 "Convert :args as widget types in WIDGET." |
1019 (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args))) | 1115 (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args))) |
1020 widget) | 1116 widget) |
1117 | |
1118 (defun widget-value-convert-widget (widget) | |
1119 "Initialize :value from :args in WIDGET." | |
1120 (let ((args (widget-get widget :args))) | |
1121 (when args | |
1122 (widget-put widget :value (car args)) | |
1123 ;; Don't convert :value here, as this is done in `widget-convert'. | |
1124 ;; (widget-put widget :value (widget-apply widget | |
1125 ;; :value-to-internal (car args))) | |
1126 (widget-put widget :args nil))) | |
1127 widget) | |
1128 | |
1129 (defun widget-value-value-get (widget) | |
1130 "Return the :value property of WIDGET." | |
1131 (widget-get widget :value)) | |
1021 | 1132 |
1022 ;;; The `default' Widget. | 1133 ;;; The `default' Widget. |
1023 | 1134 |
1024 (define-widget 'default nil | 1135 (define-widget 'default nil |
1025 "Basic widget other widgets are derived from." | 1136 "Basic widget other widgets are derived from." |
1037 :menu-tag-get 'widget-default-menu-tag-get | 1148 :menu-tag-get 'widget-default-menu-tag-get |
1038 :validate (lambda (widget) nil) | 1149 :validate (lambda (widget) nil) |
1039 :active 'widget-default-active | 1150 :active 'widget-default-active |
1040 :activate 'widget-specify-active | 1151 :activate 'widget-specify-active |
1041 :deactivate 'widget-default-deactivate | 1152 :deactivate 'widget-default-deactivate |
1153 :mouse-down-action (lambda (widget event) nil) | |
1042 :action 'widget-default-action | 1154 :action 'widget-default-action |
1043 :notify 'widget-default-notify | 1155 :notify 'widget-default-notify |
1044 :prompt-value 'widget-default-prompt-value) | 1156 :prompt-value 'widget-default-prompt-value) |
1045 | 1157 |
1046 (defun widget-default-create (widget) | 1158 (defun widget-default-create (widget) |
1231 | 1343 |
1232 ;;; The `item' Widget. | 1344 ;;; The `item' Widget. |
1233 | 1345 |
1234 (define-widget 'item 'default | 1346 (define-widget 'item 'default |
1235 "Constant items for inclusion in other widgets." | 1347 "Constant items for inclusion in other widgets." |
1236 :convert-widget 'widget-item-convert-widget | 1348 :convert-widget 'widget-value-convert-widget |
1237 :value-create 'widget-item-value-create | 1349 :value-create 'widget-item-value-create |
1238 :value-delete 'ignore | 1350 :value-delete 'ignore |
1239 :value-get 'widget-item-value-get | 1351 :value-get 'widget-value-value-get |
1240 :match 'widget-item-match | 1352 :match 'widget-item-match |
1241 :match-inline 'widget-item-match-inline | 1353 :match-inline 'widget-item-match-inline |
1242 :action 'widget-item-action | 1354 :action 'widget-item-action |
1243 :format "%t\n") | 1355 :format "%t\n") |
1244 | |
1245 (defun widget-item-convert-widget (widget) | |
1246 ;; Initialize :value from :args in WIDGET. | |
1247 (let ((args (widget-get widget :args))) | |
1248 (when args | |
1249 (widget-put widget :value (widget-apply widget | |
1250 :value-to-internal (car args))) | |
1251 (widget-put widget :args nil))) | |
1252 widget) | |
1253 | 1356 |
1254 (defun widget-item-value-create (widget) | 1357 (defun widget-item-value-create (widget) |
1255 ;; Insert the printed representation of the value. | 1358 ;; Insert the printed representation of the value. |
1256 (let ((standard-output (current-buffer))) | 1359 (let ((standard-output (current-buffer))) |
1257 (princ (widget-get widget :value)))) | 1360 (princ (widget-get widget :value)))) |
1270 (cons head (subseq values (length value)))))))) | 1373 (cons head (subseq values (length value)))))))) |
1271 | 1374 |
1272 (defun widget-item-action (widget &optional event) | 1375 (defun widget-item-action (widget &optional event) |
1273 ;; Just notify itself. | 1376 ;; Just notify itself. |
1274 (widget-apply widget :notify widget event)) | 1377 (widget-apply widget :notify widget event)) |
1275 | |
1276 (defun widget-item-value-get (widget) | |
1277 ;; Items are simple. | |
1278 (widget-get widget :value)) | |
1279 | 1378 |
1280 ;;; The `push-button' Widget. | 1379 ;;; The `push-button' Widget. |
1281 | 1380 |
1282 (defcustom widget-push-button-gui t | 1381 (defcustom widget-push-button-gui t |
1283 "If non nil, use GUI push buttons when available." | 1382 "If non nil, use GUI push buttons when available." |
1308 (progn | 1407 (progn |
1309 (unless gui | 1408 (unless gui |
1310 (setq gui (make-gui-button tag 'widget-gui-action widget)) | 1409 (setq gui (make-gui-button tag 'widget-gui-action widget)) |
1311 (push (cons tag gui) widget-push-button-cache)) | 1410 (push (cons tag gui) widget-push-button-cache)) |
1312 (widget-glyph-insert-glyph widget text | 1411 (widget-glyph-insert-glyph widget text |
1313 (make-glyph (car (aref gui 1))))) | 1412 (make-glyph (nth 0 (aref gui 1))) |
1413 (make-glyph (nth 1 (aref gui 1))) | |
1414 (make-glyph (nth 2 (aref gui 1))))) | |
1314 (insert text)))) | 1415 (insert text)))) |
1315 | 1416 |
1316 (defun widget-gui-action (widget) | 1417 (defun widget-gui-action (widget) |
1317 "Apply :action for WIDGET." | 1418 "Apply :action for WIDGET." |
1318 (widget-apply-action widget (this-command-keys))) | 1419 (widget-apply-action widget (this-command-keys))) |
1330 "A link to an info file." | 1431 "A link to an info file." |
1331 :action 'widget-info-link-action) | 1432 :action 'widget-info-link-action) |
1332 | 1433 |
1333 (defun widget-info-link-action (widget &optional event) | 1434 (defun widget-info-link-action (widget &optional event) |
1334 "Open the info node specified by WIDGET." | 1435 "Open the info node specified by WIDGET." |
1335 (Info-goto-node (widget-value widget)) | 1436 (Info-goto-node (widget-value widget))) |
1336 ;; Steal button release event. | |
1337 (if (and (fboundp 'button-press-event-p) | |
1338 (fboundp 'next-command-event)) | |
1339 ;; XEmacs | |
1340 (and event | |
1341 (button-press-event-p event) | |
1342 (next-command-event)) | |
1343 ;; Emacs | |
1344 (when (memq 'down (event-modifiers event)) | |
1345 (read-event)))) | |
1346 | 1437 |
1347 ;;; The `url-link' Widget. | 1438 ;;; The `url-link' Widget. |
1348 | 1439 |
1349 (define-widget 'url-link 'link | 1440 (define-widget 'url-link 'link |
1350 "A link to an www page." | 1441 "A link to an www page." |
1357 | 1448 |
1358 ;;; The `editable-field' Widget. | 1449 ;;; The `editable-field' Widget. |
1359 | 1450 |
1360 (define-widget 'editable-field 'default | 1451 (define-widget 'editable-field 'default |
1361 "An editable text field." | 1452 "An editable text field." |
1362 :convert-widget 'widget-item-convert-widget | 1453 :convert-widget 'widget-value-convert-widget |
1363 :keymap widget-field-keymap | 1454 :keymap widget-field-keymap |
1364 :format "%v" | 1455 :format "%v" |
1365 :value "" | 1456 :value "" |
1457 :prompt-internal 'widget-field-prompt-internal | |
1458 :prompt-history 'widget-field-history | |
1459 :prompt-value 'widget-field-prompt-value | |
1366 :action 'widget-field-action | 1460 :action 'widget-field-action |
1367 :validate 'widget-field-validate | 1461 :validate 'widget-field-validate |
1368 :valid-regexp "" | 1462 :valid-regexp "" |
1369 :error "No match" | 1463 :error "No match" |
1370 :value-create 'widget-field-value-create | 1464 :value-create 'widget-field-value-create |
1371 :value-delete 'widget-field-value-delete | 1465 :value-delete 'widget-field-value-delete |
1372 :value-get 'widget-field-value-get | 1466 :value-get 'widget-field-value-get |
1373 :match 'widget-field-match) | 1467 :match 'widget-field-match) |
1374 | 1468 |
1375 ;; History of field minibuffer edits. | 1469 (defvar widget-field-history nil |
1376 (defvar widget-field-history nil) | 1470 "History of field minibuffer edits.") |
1471 | |
1472 (defun widget-field-prompt-internal (widget prompt initial history) | |
1473 ;; Read string for WIDGET promptinhg with PROMPT. | |
1474 ;; INITIAL is the initial input and HISTORY is a symbol containing | |
1475 ;; the earlier input. | |
1476 (read-string prompt initial history)) | |
1477 | |
1478 (defun widget-field-prompt-value (widget prompt value unbound) | |
1479 ;; Prompt for a string. | |
1480 (let ((initial (if unbound | |
1481 nil | |
1482 (cons (widget-apply widget :value-to-internal | |
1483 value) 0))) | |
1484 (history (widget-get widget :prompt-history))) | |
1485 (let ((answer (widget-apply widget | |
1486 :prompt-internal prompt initial history))) | |
1487 (widget-apply widget :value-to-external answer)))) | |
1377 | 1488 |
1378 (defun widget-field-action (widget &optional event) | 1489 (defun widget-field-action (widget &optional event) |
1379 ;; Edit the value in the minibuffer. | 1490 ;; Edit the value in the minibuffer. |
1380 (let ((tag (widget-apply widget :menu-tag-get)) | 1491 (let ((invalid (widget-apply widget :validate))) |
1381 (invalid (widget-apply widget :validate))) | 1492 (let ((prompt (concat (widget-apply widget :menu-tag-get) ": ")) |
1382 (when invalid | 1493 (value (unless invalid |
1383 (error (widget-get invalid :error))) | 1494 (widget-value widget)))) |
1384 (widget-value-set widget | 1495 (let ((answer (widget-apply widget :prompt-value prompt value invalid) )) |
1385 (widget-apply widget | 1496 (widget-value-set widget answer))) |
1386 :value-to-external | |
1387 (read-string (concat tag ": ") | |
1388 (widget-apply | |
1389 widget | |
1390 :value-to-internal | |
1391 (widget-value widget)) | |
1392 'widget-field-history))) | |
1393 (widget-apply widget :notify widget event) | 1497 (widget-apply widget :notify widget event) |
1394 (widget-setup))) | 1498 (widget-setup))) |
1395 | 1499 |
1396 (defun widget-field-validate (widget) | 1500 (defun widget-field-validate (widget) |
1397 ;; Valid if the content matches `:valid-regexp'. | 1501 ;; Valid if the content matches `:valid-regexp'. |
1447 (not (zerop size)) | 1551 (not (zerop size)) |
1448 (> to from) | 1552 (> to from) |
1449 (eq (char-after (1- to)) ?\ )) | 1553 (eq (char-after (1- to)) ?\ )) |
1450 (setq to (1- to))) | 1554 (setq to (1- to))) |
1451 (let ((result (buffer-substring-no-properties from to))) | 1555 (let ((result (buffer-substring-no-properties from to))) |
1556 (when (string-match "XEmacs" emacs-version) | |
1557 ;; XEmacs 20.1 bug: b-s-n-p doesn't clear all properties. | |
1558 (setq result (format "%s" result))) | |
1452 (when secret | 1559 (when secret |
1453 (let ((index 0)) | 1560 (let ((index 0)) |
1454 (while (< (+ from index) to) | 1561 (while (< (+ from index) to) |
1455 (aset result index | 1562 (aset result index |
1456 (get-text-property (+ from index) 'secret)) | 1563 (get-text-property (+ from index) 'secret)) |
1480 :void '(item :format "invalid (%t)\n") | 1587 :void '(item :format "invalid (%t)\n") |
1481 :value-create 'widget-choice-value-create | 1588 :value-create 'widget-choice-value-create |
1482 :value-delete 'widget-children-value-delete | 1589 :value-delete 'widget-children-value-delete |
1483 :value-get 'widget-choice-value-get | 1590 :value-get 'widget-choice-value-get |
1484 :value-inline 'widget-choice-value-inline | 1591 :value-inline 'widget-choice-value-inline |
1592 :mouse-down-action 'widget-choice-mouse-down-action | |
1485 :action 'widget-choice-action | 1593 :action 'widget-choice-action |
1486 :error "Make a choice" | 1594 :error "Make a choice" |
1487 :validate 'widget-choice-validate | 1595 :validate 'widget-choice-validate |
1488 :match 'widget-choice-match | 1596 :match 'widget-choice-match |
1489 :match-inline 'widget-choice-match-inline) | 1597 :match-inline 'widget-choice-match-inline) |
1514 | 1622 |
1515 (defun widget-choice-value-inline (widget) | 1623 (defun widget-choice-value-inline (widget) |
1516 ;; Get value of the child widget. | 1624 ;; Get value of the child widget. |
1517 (widget-apply (car (widget-get widget :children)) :value-inline)) | 1625 (widget-apply (car (widget-get widget :children)) :value-inline)) |
1518 | 1626 |
1627 (defcustom widget-choice-toggle nil | |
1628 "If non-nil, a binary choice will just toggle between the values. | |
1629 Otherwise, the user will explicitly have to choose between the values | |
1630 when he activate the menu." | |
1631 :type 'boolean | |
1632 :group 'widgets) | |
1633 | |
1634 (defun widget-choice-mouse-down-action (widget &optional event) | |
1635 ;; Return non-nil if we need a menu. | |
1636 (let ((args (widget-get widget :args)) | |
1637 (old (widget-get widget :choice))) | |
1638 (cond ((not window-system) | |
1639 ;; No place to pop up a menu. | |
1640 nil) | |
1641 ((not (or (fboundp 'x-popup-menu) (fboundp 'popup-menu))) | |
1642 ;; No way to pop up a menu. | |
1643 nil) | |
1644 ((< (length args) 2) | |
1645 ;; Empty or singleton list, just return the value. | |
1646 nil) | |
1647 ((> (length args) widget-menu-max-size) | |
1648 ;; Too long, prompt. | |
1649 nil) | |
1650 ((> (length args) 2) | |
1651 ;; Reasonable sized list, use menu. | |
1652 t) | |
1653 ((and widget-choice-toggle (memq old args)) | |
1654 ;; We toggle. | |
1655 nil) | |
1656 (t | |
1657 ;; Ask which of the two. | |
1658 t)))) | |
1659 | |
1519 (defun widget-choice-action (widget &optional event) | 1660 (defun widget-choice-action (widget &optional event) |
1520 ;; Make a choice. | 1661 ;; Make a choice. |
1521 (let ((args (widget-get widget :args)) | 1662 (let ((args (widget-get widget :args)) |
1522 (old (widget-get widget :choice)) | 1663 (old (widget-get widget :choice)) |
1523 (tag (widget-apply widget :menu-tag-get)) | 1664 (tag (widget-apply widget :menu-tag-get)) |
1532 (setq current | 1673 (setq current |
1533 (cond ((= (length args) 0) | 1674 (cond ((= (length args) 0) |
1534 nil) | 1675 nil) |
1535 ((= (length args) 1) | 1676 ((= (length args) 1) |
1536 (nth 0 args)) | 1677 (nth 0 args)) |
1537 ((and (= (length args) 2) | 1678 ((and widget-choice-toggle |
1679 (= (length args) 2) | |
1538 (memq old args)) | 1680 (memq old args)) |
1539 (if (eq old (nth 0 args)) | 1681 (if (eq old (nth 0 args)) |
1540 (nth 1 args) | 1682 (nth 1 args) |
1541 (nth 0 args))) | 1683 (nth 0 args))) |
1542 (t | 1684 (t |
1787 | 1929 |
1788 ;;; The `choice-item' Widget. | 1930 ;;; The `choice-item' Widget. |
1789 | 1931 |
1790 (define-widget 'choice-item 'item | 1932 (define-widget 'choice-item 'item |
1791 "Button items that delegate action events to their parents." | 1933 "Button items that delegate action events to their parents." |
1792 :action 'widget-choice-item-action | 1934 :action 'widget-parent-action |
1793 :format "%[%t%] \n") | 1935 :format "%[%t%] \n") |
1794 | |
1795 (defun widget-choice-item-action (widget &optional event) | |
1796 ;; Tell parent what happened. | |
1797 (widget-apply (widget-get widget :parent) :action event)) | |
1798 | 1936 |
1799 ;;; The `radio-button' Widget. | 1937 ;;; The `radio-button' Widget. |
1800 | 1938 |
1801 (define-widget 'radio-button 'toggle | 1939 (define-widget 'radio-button 'toggle |
1802 "A radio button for use in the `radio' widget." | 1940 "A radio button for use in the `radio' widget." |
2015 :entry-format "%i %d %v" | 2153 :entry-format "%i %d %v" |
2016 :menu-tag "editable-list" | 2154 :menu-tag "editable-list" |
2017 :value-create 'widget-editable-list-value-create | 2155 :value-create 'widget-editable-list-value-create |
2018 :value-delete 'widget-children-value-delete | 2156 :value-delete 'widget-children-value-delete |
2019 :value-get 'widget-editable-list-value-get | 2157 :value-get 'widget-editable-list-value-get |
2020 :validate 'widget-editable-list-validate | 2158 :validate 'widget-children-validate |
2021 :match 'widget-editable-list-match | 2159 :match 'widget-editable-list-match |
2022 :match-inline 'widget-editable-list-match-inline | 2160 :match-inline 'widget-editable-list-match-inline |
2023 :insert-before 'widget-editable-list-insert-before | 2161 :insert-before 'widget-editable-list-insert-before |
2024 :delete-at 'widget-editable-list-delete-at) | 2162 :delete-at 'widget-editable-list-delete-at) |
2025 | 2163 |
2059 | 2197 |
2060 (defun widget-editable-list-value-get (widget) | 2198 (defun widget-editable-list-value-get (widget) |
2061 ;; Get value of the child widget. | 2199 ;; Get value of the child widget. |
2062 (apply 'append (mapcar (lambda (child) (widget-apply child :value-inline)) | 2200 (apply 'append (mapcar (lambda (child) (widget-apply child :value-inline)) |
2063 (widget-get widget :children)))) | 2201 (widget-get widget :children)))) |
2064 | |
2065 (defun widget-editable-list-validate (widget) | |
2066 ;; All the chilren must be valid. | |
2067 (let ((children (widget-get widget :children)) | |
2068 child found) | |
2069 (while (and children (not found)) | |
2070 (setq child (car children) | |
2071 children (cdr children) | |
2072 found (widget-apply child :validate))) | |
2073 found)) | |
2074 | 2202 |
2075 (defun widget-editable-list-match (widget value) | 2203 (defun widget-editable-list-match (widget value) |
2076 ;; Value must be a list and all the members must match the type. | 2204 ;; Value must be a list and all the members must match the type. |
2077 (and (listp value) | 2205 (and (listp value) |
2078 (null (cdr (widget-editable-list-match-inline widget value))))) | 2206 (null (cdr (widget-editable-list-match-inline widget value))))) |
2193 :convert-widget 'widget-types-convert-widget | 2321 :convert-widget 'widget-types-convert-widget |
2194 :format "%v" | 2322 :format "%v" |
2195 :value-create 'widget-group-value-create | 2323 :value-create 'widget-group-value-create |
2196 :value-delete 'widget-children-value-delete | 2324 :value-delete 'widget-children-value-delete |
2197 :value-get 'widget-editable-list-value-get | 2325 :value-get 'widget-editable-list-value-get |
2198 :validate 'widget-editable-list-validate | 2326 :validate 'widget-children-validate |
2199 :match 'widget-group-match | 2327 :match 'widget-group-match |
2200 :match-inline 'widget-group-match-inline) | 2328 :match-inline 'widget-group-match-inline) |
2201 | 2329 |
2202 (defun widget-group-value-create (widget) | 2330 (defun widget-group-value-create (widget) |
2203 ;; Create each component. | 2331 ;; Create each component. |
2282 (define-widget 'variable-item 'const | 2410 (define-widget 'variable-item 'const |
2283 "An immutable variable name." | 2411 "An immutable variable name." |
2284 :format "%v\n%h" | 2412 :format "%v\n%h" |
2285 :documentation-property 'variable-documentation) | 2413 :documentation-property 'variable-documentation) |
2286 | 2414 |
2415 (defvar widget-string-prompt-value-history nil | |
2416 "History of input to `widget-string-prompt-value'.") | |
2417 | |
2287 (define-widget 'string 'editable-field | 2418 (define-widget 'string 'editable-field |
2288 "A string" | 2419 "A string" |
2289 :prompt-value 'widget-string-prompt-value | |
2290 :tag "String" | 2420 :tag "String" |
2291 :format "%[%t%]: %v") | 2421 :format "%{%t%}: %v" |
2292 | 2422 :prompt-history 'widget-string-prompt-value-history) |
2293 (defvar widget-string-prompt-value-history nil | |
2294 "History of input to `widget-string-prompt-value'.") | |
2295 | |
2296 (defun widget-string-prompt-value (widget prompt value unbound) | |
2297 ;; Read a string. | |
2298 (read-string prompt (if unbound nil (cons value 1)) | |
2299 'widget-string-prompt-value-history)) | |
2300 | 2423 |
2301 (define-widget 'regexp 'string | 2424 (define-widget 'regexp 'string |
2302 "A regular expression." | 2425 "A regular expression." |
2303 :match 'widget-regexp-match | 2426 :match 'widget-regexp-match |
2304 :validate 'widget-regexp-validate | 2427 :validate 'widget-regexp-validate |
2305 :tag "Regexp") | 2428 :tag "Regexp") |
2306 | 2429 |
2307 (defun widget-regexp-match (widget value) | 2430 (defun widget-regexp-match (widget value) |
2308 ;; Match valid regexps. | 2431 ;; Match valid regexps. |
2309 (and (stringp value) | 2432 (and (stringp value) |
2310 (condition-case data | 2433 (condition-case nil |
2311 (prog1 t | 2434 (prog1 t |
2312 (string-match value "")) | 2435 (string-match value "")) |
2313 (error nil)))) | 2436 (error nil)))) |
2314 | 2437 |
2315 (defun widget-regexp-validate (widget) | 2438 (defun widget-regexp-validate (widget) |
2323 | 2446 |
2324 (define-widget 'file 'string | 2447 (define-widget 'file 'string |
2325 "A file widget. | 2448 "A file widget. |
2326 It will read a file name from the minibuffer when activated." | 2449 It will read a file name from the minibuffer when activated." |
2327 :prompt-value 'widget-file-prompt-value | 2450 :prompt-value 'widget-file-prompt-value |
2328 :format "%[%t%]: %v" | 2451 :format "%{%t%}: %v" |
2329 :tag "File" | 2452 :tag "File" |
2330 :action 'widget-file-action) | 2453 :action 'widget-file-action) |
2331 | 2454 |
2332 (defun widget-file-prompt-value (widget prompt value unbound) | 2455 (defun widget-file-prompt-value (widget prompt value unbound) |
2333 ;; Read file from minibuffer. | 2456 ;; Read file from minibuffer. |
2334 (abbreviate-file-name | 2457 (abbreviate-file-name |
2335 (if unbound | 2458 (if unbound |
2336 (read-file-name prompt) | 2459 (read-file-name prompt) |
2337 (let ((prompt2 (concat prompt "(default `" value "') ")) | 2460 (let ((prompt2 (format "%s (default %s) " prompt value)) |
2338 (dir (file-name-directory value)) | 2461 (dir (file-name-directory value)) |
2339 (file (file-name-nondirectory value)) | 2462 (file (file-name-nondirectory value)) |
2340 (must-match (widget-get widget :must-match))) | 2463 (must-match (widget-get widget :must-match))) |
2341 (read-file-name prompt2 dir nil must-match file))))) | 2464 (read-file-name prompt2 dir nil must-match file))))) |
2342 | 2465 |
2356 (define-widget 'directory 'file | 2479 (define-widget 'directory 'file |
2357 "A directory widget. | 2480 "A directory widget. |
2358 It will read a directory name from the minibuffer when activated." | 2481 It will read a directory name from the minibuffer when activated." |
2359 :tag "Directory") | 2482 :tag "Directory") |
2360 | 2483 |
2361 (define-widget 'symbol 'string | 2484 (defvar widget-symbol-prompt-value-history nil |
2485 "History of input to `widget-symbol-prompt-value'.") | |
2486 | |
2487 (define-widget 'symbol 'editable-field | |
2362 "A lisp symbol." | 2488 "A lisp symbol." |
2363 :value nil | 2489 :value nil |
2364 :tag "Symbol" | 2490 :tag "Symbol" |
2491 :format "%{%t%}: %v" | |
2365 :match (lambda (widget value) (symbolp value)) | 2492 :match (lambda (widget value) (symbolp value)) |
2493 :prompt-internal 'widget-symbol-prompt-internal | |
2494 :prompt-match 'symbolp | |
2495 :prompt-history 'widget-symbol-prompt-value-history | |
2366 :value-to-internal (lambda (widget value) | 2496 :value-to-internal (lambda (widget value) |
2367 (if (symbolp value) | 2497 (if (symbolp value) |
2368 (symbol-name value) | 2498 (symbol-name value) |
2369 value)) | 2499 value)) |
2370 :value-to-external (lambda (widget value) | 2500 :value-to-external (lambda (widget value) |
2371 (if (stringp value) | 2501 (if (stringp value) |
2372 (intern value) | 2502 (intern value) |
2373 value))) | 2503 value))) |
2374 | 2504 |
2505 (defun widget-symbol-prompt-internal (widget prompt initial history) | |
2506 ;; Read file from minibuffer. | |
2507 (let ((answer (completing-read prompt obarray | |
2508 (widget-get widget :prompt-match) | |
2509 nil initial history))) | |
2510 (if (and (stringp answer) | |
2511 (not (zerop (length answer)))) | |
2512 answer | |
2513 (error "No value")))) | |
2514 | |
2515 (defvar widget-function-prompt-value-history nil | |
2516 "History of input to `widget-function-prompt-value'.") | |
2517 | |
2375 (define-widget 'function 'sexp | 2518 (define-widget 'function 'sexp |
2376 ;; Should complete on functions. | |
2377 "A lisp function." | 2519 "A lisp function." |
2520 :prompt-value 'widget-field-prompt-value | |
2521 :prompt-internal 'widget-symbol-prompt-internal | |
2522 :prompt-match 'fboundp | |
2523 :prompt-history 'widget-function-prompt-value-history | |
2524 :action 'widget-field-action | |
2378 :tag "Function") | 2525 :tag "Function") |
2526 | |
2527 (defvar widget-variable-prompt-value-history nil | |
2528 "History of input to `widget-variable-prompt-value'.") | |
2379 | 2529 |
2380 (define-widget 'variable 'symbol | 2530 (define-widget 'variable 'symbol |
2381 ;; Should complete on variables. | 2531 ;; Should complete on variables. |
2382 "A lisp variable." | 2532 "A lisp variable." |
2533 :prompt-match 'boundp | |
2534 :prompt-history 'widget-variable-prompt-value-history | |
2383 :tag "Variable") | 2535 :tag "Variable") |
2384 | 2536 |
2385 (define-widget 'sexp 'string | 2537 (define-widget 'sexp 'editable-field |
2386 "An arbitrary lisp expression." | 2538 "An arbitrary lisp expression." |
2387 :tag "Lisp expression" | 2539 :tag "Lisp expression" |
2540 :format "%{%t%}: %v" | |
2388 :value nil | 2541 :value nil |
2389 :validate 'widget-sexp-validate | 2542 :validate 'widget-sexp-validate |
2390 :match (lambda (widget value) t) | 2543 :match (lambda (widget value) t) |
2391 :value-to-internal 'widget-sexp-value-to-internal | 2544 :value-to-internal 'widget-sexp-value-to-internal |
2392 :value-to-external (lambda (widget value) (read value)) | 2545 :value-to-external (lambda (widget value) (read value)) |
2546 :prompt-history 'widget-sexp-prompt-value-history | |
2393 :prompt-value 'widget-sexp-prompt-value) | 2547 :prompt-value 'widget-sexp-prompt-value) |
2394 | 2548 |
2395 (defun widget-sexp-value-to-internal (widget value) | 2549 (defun widget-sexp-value-to-internal (widget value) |
2396 ;; Use pp for printer representation. | 2550 ;; Use pp for printer representation. |
2397 (let ((pp (pp-to-string value))) | 2551 (let ((pp (pp-to-string value))) |
2428 "History of input to `widget-sexp-prompt-value'.") | 2582 "History of input to `widget-sexp-prompt-value'.") |
2429 | 2583 |
2430 (defun widget-sexp-prompt-value (widget prompt value unbound) | 2584 (defun widget-sexp-prompt-value (widget prompt value unbound) |
2431 ;; Read an arbitrary sexp. | 2585 ;; Read an arbitrary sexp. |
2432 (let ((found (read-string prompt | 2586 (let ((found (read-string prompt |
2433 (if unbound nil (cons (prin1-to-string value) 1)) | 2587 (if unbound nil (cons (prin1-to-string value) 0)) |
2434 'widget-sexp-prompt-value))) | 2588 (widget-get widget :prompt-history)))) |
2435 (let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*")))) | 2589 (save-excursion |
2436 (erase-buffer) | 2590 (let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*")))) |
2437 (insert found) | 2591 (erase-buffer) |
2438 (goto-char (point-min)) | 2592 (insert found) |
2439 (let ((answer (read buffer))) | 2593 (goto-char (point-min)) |
2440 (unless (eobp) | 2594 (let ((answer (read buffer))) |
2441 (error "Junk at end of expression: %s" | 2595 (unless (eobp) |
2442 (buffer-substring (point) (point-max)))) | 2596 (error "Junk at end of expression: %s" |
2443 answer)))) | 2597 (buffer-substring (point) (point-max)))) |
2444 | 2598 answer))))) |
2599 | |
2445 (define-widget 'integer 'sexp | 2600 (define-widget 'integer 'sexp |
2446 "An integer." | 2601 "An integer." |
2447 :tag "Integer" | 2602 :tag "Integer" |
2448 :value 0 | 2603 :value 0 |
2449 :type-error "This field should contain an integer" | 2604 :type-error "This field should contain an integer" |
2451 (if (integerp value) | 2606 (if (integerp value) |
2452 (prin1-to-string value) | 2607 (prin1-to-string value) |
2453 value)) | 2608 value)) |
2454 :match (lambda (widget value) (integerp value))) | 2609 :match (lambda (widget value) (integerp value))) |
2455 | 2610 |
2456 (define-widget 'character 'string | 2611 (define-widget 'character 'editable-field |
2457 "An character." | 2612 "An character." |
2458 :tag "Character" | 2613 :tag "Character" |
2459 :value 0 | 2614 :value 0 |
2460 :size 1 | 2615 :size 1 |
2461 :format "%{%t%}: %v\n" | 2616 :format "%{%t%}: %v\n" |
2462 :valid-regexp "\\`.\\'" | 2617 :valid-regexp "\\`.\\'" |
2463 :error "This field should contain a single character" | 2618 :error "This field should contain a single character" |
2464 :value-to-internal (lambda (widget value) | 2619 :value-to-internal (lambda (widget value) |
2465 (if (integerp value) | 2620 (if (stringp value) |
2466 (char-to-string value) | 2621 value |
2467 value)) | 2622 (char-to-string value))) |
2468 :value-to-external (lambda (widget value) | 2623 :value-to-external (lambda (widget value) |
2469 (if (stringp value) | 2624 (if (stringp value) |
2470 (aref value 0) | 2625 (aref value 0) |
2471 value)) | 2626 value)) |
2472 :match (lambda (widget value) (integerp value))) | 2627 :match (lambda (widget value) |
2628 (if (fboundp 'characterp) | |
2629 (characterp value) | |
2630 (integerp value)))) | |
2473 | 2631 |
2474 (define-widget 'number 'sexp | 2632 (define-widget 'number 'sexp |
2475 "A floating point number." | 2633 "A floating point number." |
2476 :tag "Number" | 2634 :tag "Number" |
2477 :value 0.0 | 2635 :value 0.0 |
2516 (widget-apply widget :value-to-internal value)))) | 2674 (widget-apply widget :value-to-internal value)))) |
2517 | 2675 |
2518 (define-widget 'choice 'menu-choice | 2676 (define-widget 'choice 'menu-choice |
2519 "A union of several sexp types." | 2677 "A union of several sexp types." |
2520 :tag "Choice" | 2678 :tag "Choice" |
2521 :format "%[%t%]: %v") | 2679 :format "%[%t%]: %v" |
2680 :prompt-value 'widget-choice-prompt-value) | |
2681 | |
2682 (defun widget-choice-prompt-value (widget prompt value unbound) | |
2683 "Make a choice." | |
2684 (let ((args (widget-get widget :args)) | |
2685 (completion-ignore-case (widget-get widget :case-fold)) | |
2686 current choices old) | |
2687 ;; Find the first arg that match VALUE. | |
2688 (let ((look args)) | |
2689 (while look | |
2690 (if (widget-apply (car look) :match value) | |
2691 (setq old (car look) | |
2692 look nil) | |
2693 (setq look (cdr look))))) | |
2694 ;; Find new choice. | |
2695 (setq current | |
2696 (cond ((= (length args) 0) | |
2697 nil) | |
2698 ((= (length args) 1) | |
2699 (nth 0 args)) | |
2700 ((and (= (length args) 2) | |
2701 (memq old args)) | |
2702 (if (eq old (nth 0 args)) | |
2703 (nth 1 args) | |
2704 (nth 0 args))) | |
2705 (t | |
2706 (while args | |
2707 (setq current (car args) | |
2708 args (cdr args)) | |
2709 (setq choices | |
2710 (cons (cons (widget-apply current :menu-tag-get) | |
2711 current) | |
2712 choices))) | |
2713 (let ((val (completing-read prompt choices nil t))) | |
2714 (if (stringp val) | |
2715 (let ((try (try-completion val choices))) | |
2716 (when (stringp try) | |
2717 (setq val try)) | |
2718 (cdr (assoc val choices))) | |
2719 nil))))) | |
2720 (if current | |
2721 (widget-prompt-value current prompt nil t) | |
2722 value))) | |
2522 | 2723 |
2523 (define-widget 'radio 'radio-button-choice | 2724 (define-widget 'radio 'radio-button-choice |
2524 "A union of several sexp types." | 2725 "A union of several sexp types." |
2525 :tag "Choice" | 2726 :tag "Choice" |
2526 :format "%{%t%}:\n%v") | 2727 :format "%{%t%}:\n%v" |
2728 :prompt-value 'widget-choice-prompt-value) | |
2527 | 2729 |
2528 (define-widget 'repeat 'editable-list | 2730 (define-widget 'repeat 'editable-list |
2529 "A variable length homogeneous list." | 2731 "A variable length homogeneous list." |
2530 :tag "Repeat" | 2732 :tag "Repeat" |
2531 :format "%{%t%}:\n%v%i\n") | 2733 :format "%{%t%}:\n%v%i\n") |
2537 | 2739 |
2538 (define-widget 'boolean 'toggle | 2740 (define-widget 'boolean 'toggle |
2539 "To be nil or non-nil, that is the question." | 2741 "To be nil or non-nil, that is the question." |
2540 :tag "Boolean" | 2742 :tag "Boolean" |
2541 :prompt-value 'widget-boolean-prompt-value | 2743 :prompt-value 'widget-boolean-prompt-value |
2542 :format "%{%t%}: %[%v%]\n") | 2744 :format "%[%t%]: %v\n") |
2543 | 2745 |
2544 (defun widget-boolean-prompt-value (widget prompt value unbound) | 2746 (defun widget-boolean-prompt-value (widget prompt value unbound) |
2545 ;; Toggle a boolean. | 2747 ;; Toggle a boolean. |
2546 (cond (unbound | 2748 (y-or-n-p prompt)) |
2547 (y-or-n-p prompt)) | |
2548 (value | |
2549 (message "Off") | |
2550 nil) | |
2551 (t | |
2552 (message "On") | |
2553 t))) | |
2554 | 2749 |
2555 ;;; The `color' Widget. | 2750 ;;; The `color' Widget. |
2556 | 2751 |
2557 (define-widget 'color-item 'choice-item | 2752 (define-widget 'color-item 'choice-item |
2558 "A color name (with sample)." | 2753 "A color name (with sample)." |