Mercurial > hg > xemacs-beta
comparison lisp/wid-edit.el @ 1362:cfe4bcb9bdd4
[xemacs-hg @ 2003-03-18 06:58:19 by stephent]
wid-edit.el cleanup <878yvdi2rz.fsf@tleepslib.sk.tsukuba.ac.jp>
buffers tab control doc improvements <87bs09i3w5.fsf_-_@tleepslib.sk.tsukuba.ac.jp>
author | stephent |
---|---|
date | Tue, 18 Mar 2003 06:58:24 +0000 |
parents | 1b0339b048ce |
children | 2e0147538471 |
comparison
equal
deleted
inserted
replaced
1361:ffdb1a771055 | 1362:cfe4bcb9bdd4 |
---|---|
32 | 32 |
33 ;;; Code: | 33 ;;; Code: |
34 | 34 |
35 (require 'widget) | 35 (require 'widget) |
36 | 36 |
37 (autoload 'finder-commentary "finder" nil t) | 37 ;; XEmacs: autoload of `finder-commentary' is redundant. |
38 | 38 |
39 ;;; Customization. | 39 ;;; Customization. |
40 | 40 |
41 (defgroup widgets nil | 41 (defgroup widgets nil |
42 "Customization support for the Widget Library." | 42 "Customization support for the Widget Library." |
87 | 87 |
88 ;; #### comment from GNU Emacs 21.3.50, test the first spec. | 88 ;; #### comment from GNU Emacs 21.3.50, test the first spec. |
89 ;; TTY gets special definitions here and in the next defface, because | 89 ;; TTY gets special definitions here and in the next defface, because |
90 ;; the gray colors defined for other displays cause black text on a black | 90 ;; the gray colors defined for other displays cause black text on a black |
91 ;; background, at least on light-background TTYs. | 91 ;; background, at least on light-background TTYs. |
92 (defface widget-field-face '((((type tty)) | 92 (defface widget-field-face '( |
93 ;; #### sjt sez: XEmacs doesn't like this. | |
94 ;; The Custom face editor widget shows a Lisp | |
95 ;; form, not a face structure. Does it produce | |
96 ;; the right face on TTYs? | |
97 ;; One hypothesis is that the editor doesn't | |
98 ;; grok non-default display types in the value. | |
99 (((type tty)) | |
93 (:background "yellow3") | 100 (:background "yellow3") |
94 (:foreground "black")) | 101 (:foreground "black")) |
95 (((class grayscale color) | 102 (((class grayscale color) |
96 (background light)) | 103 (background light)) |
97 (:background "gray85")) | 104 (:background "gray85")) |
149 ;; The value is actually the tail of PLIST whose car is PROP. | 156 ;; The value is actually the tail of PLIST whose car is PROP. |
150 (while (and plist (not (eq (car plist) prop))) | 157 (while (and plist (not (eq (car plist) prop))) |
151 (setq plist (cddr plist))) | 158 (setq plist (cddr plist))) |
152 plist)) | 159 plist)) |
153 | 160 |
154 (defun widget-princ-to-string (object) | 161 (defsubst widget-princ-to-string (object) |
155 "Return string representation of OBJECT, any Lisp object. | 162 "Return string representation of OBJECT, any Lisp object. |
156 No quoting characters are used; no delimiters are printed around | 163 |
157 the contents of strings." | 164 No quoting characters or string delimiters are used." |
158 (with-current-buffer (get-buffer-create " *widget-tmp*") | 165 ;(with-current-buffer (get-buffer-create " *widget-tmp*") |
159 (erase-buffer) | 166 ; (erase-buffer) |
160 (princ object (current-buffer)) | 167 ; (princ object (current-buffer)) |
161 (buffer-string))) | 168 ; (buffer-string)) |
169 (prin1-to-string object t) | |
170 ) | |
162 | 171 |
163 (defun widget-prettyprint-to-string (object) | 172 (defun widget-prettyprint-to-string (object) |
164 ;; Like pp-to-string, but uses `cl-prettyprint' | 173 "Use `cl-prettyprint' to generate a string representation of OBJECT. |
165 (with-current-buffer (get-buffer-create " *widget-tmp*") | 174 |
166 (erase-buffer) | 175 Cleans up `cl-prettyprint''s gratuitous surrounding newlines." |
176 (with-temp-buffer | |
167 (cl-prettyprint object) | 177 (cl-prettyprint object) |
168 ;; `cl-prettyprint' always surrounds the text with newlines. | 178 ;; `cl-prettyprint' always surrounds the text with newlines. |
169 (when (eq (char-after (point-min)) ?\n) | 179 (buffer-string (if (eq (char-after (point-min)) ?\n) |
170 (delete-region (point-min) (1+ (point-min)))) | 180 (1+ (point-min)) |
171 (when (eq (char-before (point-max)) ?\n) | 181 (point-min)) |
172 (delete-region (1- (point-max)) (point-max))) | 182 (if (eq (char-before (point-max)) ?\n) |
173 (buffer-string))) | 183 (1- (point-max)) |
184 (point-max))))) | |
174 | 185 |
175 (defun widget-clear-undo () | 186 (defun widget-clear-undo () |
176 "Clear all undo information." | 187 "Clear all undo information." |
177 (buffer-disable-undo) | 188 (buffer-disable-undo) |
178 (buffer-enable-undo)) | 189 (buffer-enable-undo)) |
190 | |
191 (defun widget-sublist (list start &optional end) | |
192 "Return the sublist of LIST from START to END. | |
193 If END is omitted, it defaults to the length of LIST." | |
194 (if (> start 0) (setq list (nthcdr start list))) | |
195 (if end | |
196 (if (<= end start) | |
197 nil | |
198 (setq list (copy-sequence list)) | |
199 (setcdr (nthcdr (- end start 1) list) nil) | |
200 list) | |
201 (copy-sequence list))) | |
202 | |
203 ;; Is unimplemented the right superclass? | |
204 (define-error 'missing-package "Package not installed" 'unimplemented) | |
179 | 205 |
180 (defcustom widget-menu-max-size 40 | 206 (defcustom widget-menu-max-size 40 |
181 "Largest number of items allowed in a popup-menu. | 207 "Largest number of items allowed in a popup-menu. |
182 Larger menus are read through the minibuffer." | 208 Larger menus are read through the minibuffer." |
183 :group 'widgets | 209 :group 'widgets |
204 Second argument ITEMS is a list whose members are either | 230 Second argument ITEMS is a list whose members are either |
205 (NAME . VALUE), to indicate selectable items, or just strings to | 231 (NAME . VALUE), to indicate selectable items, or just strings to |
206 indicate unselectable items. | 232 indicate unselectable items. |
207 Optional third argument EVENT is an input event. | 233 Optional third argument EVENT is an input event. |
208 | 234 |
209 The user is asked to choose between each NAME from the items alist, | 235 The user is asked to choose a NAME from the items alist, and the VALUE of |
210 and the VALUE of the chosen element will be returned. If EVENT is a | 236 the chosen element will be returned. If EVENT is a mouse event, and the |
211 mouse event, and the number of elements in items is less than | 237 number of elements in items is less than `widget-menu-max-size', a popup |
212 `widget-menu-max-size', a popup menu will be used, otherwise the | 238 menu will be used, otherwise the minibuffer is used." |
213 minibuffer." | |
214 (cond ((and (< (length items) widget-menu-max-size) | 239 (cond ((and (< (length items) widget-menu-max-size) |
215 event | 240 event |
216 (console-on-window-system-p)) | 241 (console-on-window-system-p)) |
217 ;; Pressed by the mouse. | 242 ;; Pressed by the mouse. |
218 (let ((val (get-popup-menu-response | 243 (let ((val (get-popup-menu-response |
302 | 327 |
303 ;;; Widget text specifications. | 328 ;;; Widget text specifications. |
304 ;; | 329 ;; |
305 ;; These functions are for specifying text properties. | 330 ;; These functions are for specifying text properties. |
306 | 331 |
332 ;; XEmacs: This probably should be unnecessary with end-closed extents. | |
333 ;; If it doesn't work, it should be made to work. | |
307 (defcustom widget-field-add-space t | 334 (defcustom widget-field-add-space t |
308 ;; Setting this to nil might be available, once some problems are resolved. | 335 ;; Setting this to nil might be available, once some problems are resolved. |
309 "Non-nil means add extra space at the end of editable text fields. | 336 "Non-nil means add extra space at the end of editable text fields. |
310 | 337 |
311 This is needed on all versions of Emacs. If you don't add the space, | 338 Currently should be left set to `t', because without the space it becomes |
312 it will become impossible to edit a zero size field." | 339 impossible to edit a zero size field." |
313 :type 'boolean | 340 :type 'boolean |
314 :group 'widgets) | 341 :group 'widgets) |
315 | 342 |
343 ;; #### Why aren't these used in XEmacs? | |
316 (defcustom widget-field-use-before-change | 344 (defcustom widget-field-use-before-change |
317 (and (or (> emacs-minor-version 34) | 345 (and (or (> emacs-minor-version 34) |
318 (> emacs-major-version 19)) | 346 (> emacs-major-version 19)) |
319 (not (string-match "XEmacs" emacs-version))) | 347 (not (string-match "XEmacs" emacs-version))) |
320 "Non-nil means use `before-change-functions' to track editable fields. | 348 "Non-nil means use `before-change-functions' to track editable fields. |
346 "Specify editable button for WIDGET between FROM and TO." | 374 "Specify editable button for WIDGET between FROM and TO." |
347 (save-excursion | 375 (save-excursion |
348 (goto-char to) | 376 (goto-char to) |
349 (cond ((null (widget-get widget :size)) | 377 (cond ((null (widget-get widget :size)) |
350 (forward-char 1)) | 378 (forward-char 1)) |
351 ;; #### This comment goes outside of the save-excursion in GNU | 379 ;; XEmacs: This comment goes outside of the save-excursion in GNU. |
352 ;; Terminating space is not part of the field, but necessary in | 380 ;; Terminating space is not part of the field, but necessary in |
353 ;; order for local-map to work. Remove next sexp if local-map works | 381 ;; order for local-map to work. Remove next sexp if local-map works |
354 ;; at the end of the extent. | 382 ;; at the end of the extent. |
355 (widget-field-add-space | 383 (widget-field-add-space |
356 (insert-and-inherit " "))) | 384 (insert-and-inherit " "))) |
372 (set-extent-property extent 'face face) | 400 (set-extent-property extent 'face face) |
373 (widget-handle-help-echo extent help-echo)) | 401 (widget-handle-help-echo extent help-echo)) |
374 (widget-specify-secret widget)) | 402 (widget-specify-secret widget)) |
375 | 403 |
376 (defun widget-specify-secret (field) | 404 (defun widget-specify-secret (field) |
377 "Replace text in FIELD with value of `:secret', if non-nil. | 405 "Replace text in FIELD with value of the `:secret' property, if non-nil. |
378 | 406 |
407 The value of the `:secret' property, if non-nil, must be a character. | |
379 It is an error to use this function after creating the widget but before | 408 It is an error to use this function after creating the widget but before |
380 invoking `widget-setup'." | 409 invoking `widget-setup'." |
381 (let ((secret (widget-get field :secret)) | 410 (let ((secret (widget-get field :secret)) |
382 (size (widget-get field :size))) | 411 (size (widget-get field :size))) |
383 (when secret | 412 (when secret |
890 ;;; Creating Widgets. | 919 ;;; Creating Widgets. |
891 | 920 |
892 ;;;###autoload | 921 ;;;###autoload |
893 (defun widget-create (type &rest args) | 922 (defun widget-create (type &rest args) |
894 "Create a widget of type TYPE. | 923 "Create a widget of type TYPE. |
895 The optional ARGS are additional keyword arguments." | 924 |
925 TYPE is copied, then converted to a widget using the keyword arguments ARGS." | |
896 (let ((widget (apply 'widget-convert type args))) | 926 (let ((widget (apply 'widget-convert type args))) |
897 (widget-apply widget :create) | 927 (widget-apply widget :create) |
898 widget)) | 928 widget)) |
899 | 929 |
900 (defun widget-create-child-and-convert (parent type &rest args) | 930 (defun widget-create-child-and-convert (parent type &rest args) |
901 "As a child of widget PARENT, create a widget of type TYPE. | 931 "As a child of widget PARENT, create a widget of type TYPE. |
902 The child is converted, using the keyword arguments ARGS." | 932 |
933 TYPE is copied, then converted to a widget using the keyword arguments ARGS." | |
903 (let ((widget (apply 'widget-convert type args))) | 934 (let ((widget (apply 'widget-convert type args))) |
904 (widget-put widget :parent parent) | 935 (widget-put widget :parent parent) |
905 (unless (widget-get widget :indent) | 936 (unless (widget-get widget :indent) |
906 (widget-put widget :indent (+ (or (widget-get parent :indent) 0) | 937 (widget-put widget :indent (+ (or (widget-get parent :indent) 0) |
907 (or (widget-get widget :extra-offset) 0) | 938 (or (widget-get widget :extra-offset) 0) |
909 (widget-apply widget :create) | 940 (widget-apply widget :create) |
910 widget)) | 941 widget)) |
911 | 942 |
912 (defun widget-create-child (parent type) | 943 (defun widget-create-child (parent type) |
913 "As a child of widget PARENT, create a widget of type TYPE. | 944 "As a child of widget PARENT, create a widget of type TYPE. |
914 The child is not converted." | 945 |
946 TYPE is copied, then used as a widget as-is." | |
915 (let ((widget (copy-sequence type))) | 947 (let ((widget (copy-sequence type))) |
916 (widget-put widget :parent parent) | 948 (widget-put widget :parent parent) |
917 (unless (widget-get widget :indent) | 949 (unless (widget-get widget :indent) |
918 (widget-put widget :indent (+ (or (widget-get parent :indent) 0) | 950 (widget-put widget :indent (+ (or (widget-get parent :indent) 0) |
919 (or (widget-get widget :extra-offset) 0) | 951 (or (widget-get widget :extra-offset) 0) |
920 (widget-get parent :offset)))) | 952 (widget-get parent :offset)))) |
921 (widget-apply widget :create) | 953 (widget-apply widget :create) |
922 widget)) | 954 widget)) |
923 | 955 |
924 (defun widget-create-child-value (parent type value) | 956 (defun widget-create-child-value (parent type value) |
925 "Create widget of TYPE with value VALUE." | 957 "As a child of widget PARENT, create a widget with type TYPE and value VALUE. |
958 | |
959 TYPE is copied, then used as a widget as-is." | |
926 (let ((widget (copy-sequence type))) | 960 (let ((widget (copy-sequence type))) |
927 (widget-put widget :value (widget-apply widget :value-to-internal value)) | 961 (widget-put widget :value (widget-apply widget :value-to-internal value)) |
928 (widget-put widget :parent parent) | 962 (widget-put widget :parent parent) |
929 (unless (widget-get widget :indent) | 963 (unless (widget-get widget :indent) |
930 (widget-put widget :indent (+ (or (widget-get parent :indent) 0) | 964 (widget-put widget :indent (+ (or (widget-get parent :indent) 0) |
943 (widget-apply (copy-sequence widget) :copy)) | 977 (widget-apply (copy-sequence widget) :copy)) |
944 | 978 |
945 ;;;###autoload | 979 ;;;###autoload |
946 (defun widget-convert (type &rest args) | 980 (defun widget-convert (type &rest args) |
947 "Convert TYPE to a widget without inserting it in the buffer. | 981 "Convert TYPE to a widget without inserting it in the buffer. |
948 The optional ARGS are additional keyword arguments." | 982 The optional ARGS are additional keyword arguments. |
983 | |
984 The widget's :args property is set from the longest tail of ARGS whose cdr | |
985 is not a keyword, or from the longest tail of TYPE's :args property whose | |
986 cdr is not a keyword. Keyword arguments from ARGS are set, and the :value | |
987 property (if any) is converted from external to internal format." | |
949 ;; Don't touch the type. | 988 ;; Don't touch the type. |
950 (let* ((widget (if (symbolp type) | 989 (let* ((widget (if (symbolp type) |
951 (list type) | 990 (list type) |
952 (copy-sequence type))) | 991 (copy-sequence type))) |
953 (current widget) | 992 (current widget) |
954 (keys args)) | 993 (keys args)) |
955 ;; First set the :args keyword. | 994 ;; First set the :args. |
956 (while (cdr current) ;Look in the type. | 995 (while (cdr current) ; Use first non-keyword element of type. |
957 (let ((next (car (cdr current)))) | 996 (let ((next (car (cdr current)))) |
958 (if (and (symbolp next) (eq (aref (symbol-name next) 0) ?:)) | 997 (if (keywordp next) |
959 (setq current (cdr (cdr current))) | 998 (setq current (cdr (cdr current))) |
960 (setcdr current (list :args (cdr current))) | 999 (setcdr current (list :args (cdr current))) |
961 (setq current nil)))) | 1000 (setq current nil)))) |
962 (while args ;Look in the args. | 1001 (while args ; Use first non-keyword element in ARGS. |
963 (let ((next (nth 0 args))) | 1002 (let ((next (nth 0 args))) |
964 (if (and (symbolp next) (eq (aref (symbol-name next) 0) ?:)) | 1003 (if (keywordp next) |
965 (setq args (nthcdr 2 args)) | 1004 (setq args (nthcdr 2 args)) |
966 (widget-put widget :args args) | 1005 (widget-put widget :args args) |
967 (setq args nil)))) | 1006 (setq args nil)))) |
968 ;; Then convert the widget. | 1007 ;; Then convert the widget. |
969 (setq type widget) | 1008 (setq type widget) |
1445 (error "Not in an editable field")))) | 1484 (error "Not in an editable field")))) |
1446 | 1485 |
1447 | 1486 |
1448 ;;; Setting up the buffer. | 1487 ;;; Setting up the buffer. |
1449 | 1488 |
1450 (defvar widget-field-new nil) | 1489 (defvar widget-field-new nil |
1451 ;; List of all newly created editable fields in the buffer. | 1490 "List of all newly created editable fields in the buffer.") |
1452 (make-variable-buffer-local 'widget-field-new) | 1491 (make-variable-buffer-local 'widget-field-new) |
1453 | 1492 |
1454 (defvar widget-field-list nil) | 1493 (defvar widget-field-list nil |
1455 ;; List of all editable fields in the buffer. | 1494 "List of all editable fields in the buffer.") |
1456 (make-variable-buffer-local 'widget-field-list) | 1495 (make-variable-buffer-local 'widget-field-list) |
1457 | 1496 |
1458 ;; Is this a misnomer? | 1497 ;; Is this a misnomer? |
1459 (defun widget-at (pos) | 1498 (defun widget-at (pos) |
1460 "The button or field at POS." | 1499 "The button or field at POS." |
1650 (widget-put widget :args (mapcar 'widget-copy (widget-get widget :args))) | 1689 (widget-put widget :args (mapcar 'widget-copy (widget-get widget :args))) |
1651 widget) | 1690 widget) |
1652 | 1691 |
1653 ;; Made defsubst to speed up face editor creation. | 1692 ;; Made defsubst to speed up face editor creation. |
1654 (defsubst widget-types-convert-widget (widget) | 1693 (defsubst widget-types-convert-widget (widget) |
1655 "Convert :args as widget types in WIDGET." | 1694 "Convert each member of :args in WIDGET from a widget type to a widget." |
1656 (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args))) | 1695 (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args))) |
1657 widget) | 1696 widget) |
1658 | 1697 |
1659 (defun widget-value-convert-widget (widget) | 1698 (defun widget-value-convert-widget (widget) |
1660 "Initialize :value from :args in WIDGET." | 1699 "Initialize :value from `(car :args)' in WIDGET, and reset :args." |
1661 (let ((args (widget-get widget :args))) | 1700 (let ((args (widget-get widget :args))) |
1662 (when args | 1701 (when args |
1663 (widget-put widget :value (car args)) | 1702 (widget-put widget :value (car args)) |
1664 ;; Don't convert :value here, as this is done in `widget-convert'. | 1703 ;; Don't convert :value here, as this is done in `widget-convert'. |
1665 ;; (widget-put widget :value (widget-apply widget | 1704 ;; (widget-put widget :value (widget-apply widget |
1717 value-pos) | 1756 value-pos) |
1718 (insert (widget-get widget :format)) | 1757 (insert (widget-get widget :format)) |
1719 (goto-char from) | 1758 (goto-char from) |
1720 ;; Parse escapes in format. | 1759 ;; Parse escapes in format. |
1721 ;; Coding this in C would speed up things *a lot*. | 1760 ;; Coding this in C would speed up things *a lot*. |
1761 ;; sjt sez: | |
1762 ;; There are other things to try: | |
1763 ;; 1. Use skip-chars-forward. | |
1764 ;; 2. Use a LIMIT (or narrow buffer?) in the search/skip expression. | |
1765 ;; 3. Search/skip backward to allow LIMIT to be constant. | |
1766 ;; 4. Use a char-table to dispatch to code, instead of a cond. | |
1722 (while (re-search-forward "%\\(.\\)" nil t) | 1767 (while (re-search-forward "%\\(.\\)" nil t) |
1723 (let ((escape (aref (match-string 1) 0))) | 1768 (let ((escape (aref (match-string 1) 0))) |
1724 (replace-match "" t t) | 1769 (replace-match "" t t) |
1725 (cond ((eq escape ?%) | 1770 (cond ((eq escape ?%) |
1726 (insert ?%)) | 1771 (insert ?%)) |
1838 (let ((parent (widget-get widget :parent))) | 1883 (let ((parent (widget-get widget :parent))) |
1839 (if parent | 1884 (if parent |
1840 (widget-apply parent :button-face-get) | 1885 (widget-apply parent :button-face-get) |
1841 widget-button-face)))) | 1886 widget-button-face)))) |
1842 | 1887 |
1888 ;; Shouldn't this be like `widget-default-button-face-get', and recurse, and | |
1889 ;; have a fallback? | |
1843 (defun widget-default-sample-face-get (widget) | 1890 (defun widget-default-sample-face-get (widget) |
1844 ;; Use :sample-face. | 1891 ;; Use :sample-face. |
1845 (widget-get widget :sample-face)) | 1892 (widget-get widget :sample-face)) |
1846 | 1893 |
1847 (defun widget-default-delete (widget) | 1894 (defun widget-default-delete (widget) |
1854 (doc-extent (widget-get widget :doc-extent)) | 1901 (doc-extent (widget-get widget :doc-extent)) |
1855 before-change-functions | 1902 before-change-functions |
1856 after-change-functions | 1903 after-change-functions |
1857 (inhibit-read-only t)) | 1904 (inhibit-read-only t)) |
1858 (widget-apply widget :value-delete) | 1905 (widget-apply widget :value-delete) |
1906 ;; #### In current code, these are never reinserted, but recreated. | |
1907 ;; So they should either be destroyed, or we should think about how to | |
1908 ;; reuse them. | |
1859 (when inactive-extent | 1909 (when inactive-extent |
1860 (detach-extent inactive-extent)) | 1910 (detach-extent inactive-extent)) |
1861 (when button-extent | 1911 (when button-extent |
1862 (detach-extent button-extent)) | 1912 (detach-extent button-extent)) |
1863 (when sample-extent | 1913 (when sample-extent |
1908 (or (widget-get widget :menu-tag) | 1958 (or (widget-get widget :menu-tag) |
1909 (widget-get widget :tag) | 1959 (widget-get widget :tag) |
1910 (widget-princ-to-string (widget-get widget :value)))) | 1960 (widget-princ-to-string (widget-get widget :value)))) |
1911 | 1961 |
1912 (defun widget-default-active (widget) | 1962 (defun widget-default-active (widget) |
1913 "Return t iff this widget active (user modifiable)." | 1963 "Return non-nil iff WIDGET is user-modifiable." |
1914 (and (not (widget-get widget :inactive)) | 1964 (and (not (widget-get widget :inactive)) |
1915 (let ((parent (widget-get widget :parent))) | 1965 (let ((parent (widget-get widget :parent))) |
1916 (or (null parent) | 1966 (or (null parent) |
1917 (widget-apply parent :active))))) | 1967 (widget-apply parent :active))))) |
1918 | 1968 |
1931 (defun widget-default-notify (widget child &optional event) | 1981 (defun widget-default-notify (widget child &optional event) |
1932 "Pass notification to parent." | 1982 "Pass notification to parent." |
1933 (widget-default-action widget event)) | 1983 (widget-default-action widget event)) |
1934 | 1984 |
1935 (defun widget-default-prompt-value (widget prompt value unbound) | 1985 (defun widget-default-prompt-value (widget prompt value unbound) |
1936 "Read an arbitrary value. Stolen from `set-variable'." | 1986 "Read an arbitrary value." |
1987 ;; #### XEmacs: What does this mean? | |
1988 ;; Stolen from `set-variable'. | |
1937 ;; (let ((initial (if unbound | 1989 ;; (let ((initial (if unbound |
1938 ;; nil | 1990 ;; nil |
1939 ;; It would be nice if we could do a `(cons val 1)' here. | 1991 ;; It would be nice if we could do a `(cons val 1)' here. |
1940 ;; (prin1-to-string (custom-quote value)))))) | 1992 ;; (prin1-to-string (custom-quote value)))))) |
1993 ;; XEmacs: make this use default VALUE. Need to check callers. | |
1941 (eval-minibuffer prompt)) | 1994 (eval-minibuffer prompt)) |
1942 | 1995 |
1943 ;;; The `item' Widget. | 1996 ;;; The `item' Widget. |
1944 | 1997 |
1945 (define-widget 'item 'default | 1998 (define-widget 'item 'default |
1968 (<= (length value) (length values)) | 2021 (<= (length value) (length values)) |
1969 (let ((head (widget-sublist values 0 (length value)))) | 2022 (let ((head (widget-sublist values 0 (length value)))) |
1970 (and (equal head value) | 2023 (and (equal head value) |
1971 (cons head (widget-sublist values (length value)))))))) | 2024 (cons head (widget-sublist values (length value)))))))) |
1972 | 2025 |
1973 (defun widget-sublist (list start &optional end) | |
1974 "Return the sublist of LIST from START to END. | |
1975 If END is omitted, it defaults to the length of LIST." | |
1976 (if (> start 0) (setq list (nthcdr start list))) | |
1977 (if end | |
1978 (unless (<= end start) | |
1979 (setq list (copy-sequence list)) | |
1980 (setcdr (nthcdr (- end start 1) list) nil) | |
1981 list) | |
1982 (copy-sequence list))) | |
1983 | |
1984 (defun widget-item-action (widget &optional event) | 2026 (defun widget-item-action (widget &optional event) |
1985 ;; Just notify itself. | 2027 ;; Just notify itself. |
1986 (widget-apply widget :notify widget event)) | 2028 (widget-apply widget :notify widget event)) |
1987 | 2029 |
1988 ;;; The `push-button' Widget. | 2030 ;;; The `push-button' Widget. |
1989 | 2031 |
2032 ;; XEmacs: this seems to refer to button images. How about native widgets? | |
1990 (defcustom widget-push-button-gui widget-glyph-enable | 2033 (defcustom widget-push-button-gui widget-glyph-enable |
1991 "If non nil, use GUI push buttons when available." | 2034 "If non nil, use GUI push buttons when available." |
1992 :group 'widgets | 2035 :group 'widgets |
1993 :type 'boolean) | 2036 :type 'boolean) |
1994 | 2037 |
2001 "String used as suffix for buttons." | 2044 "String used as suffix for buttons." |
2002 :type 'string | 2045 :type 'string |
2003 :group 'widget-button) | 2046 :group 'widget-button) |
2004 | 2047 |
2005 (define-widget 'push-button 'item | 2048 (define-widget 'push-button 'item |
2006 "A pushable button." | 2049 "A button which invokes an action. |
2050 | |
2051 Creators should usually specify `:action' and `:help-echo' members." | |
2007 :button-prefix "" | 2052 :button-prefix "" |
2008 :button-suffix "" | 2053 :button-suffix "" |
2009 :value-create 'widget-push-button-value-create | 2054 :value-create 'widget-push-button-value-create |
2010 :format "%[%v%]") | 2055 :format "%[%v%]") |
2011 | 2056 |
2046 "String used as suffix for links." | 2091 "String used as suffix for links." |
2047 :type 'string | 2092 :type 'string |
2048 :group 'widget-button) | 2093 :group 'widget-button) |
2049 | 2094 |
2050 (define-widget 'link 'item | 2095 (define-widget 'link 'item |
2051 "An embedded link." | 2096 "An embedded link. |
2097 | |
2098 This is an abstract widget. Subclasses should usually specify `:action' | |
2099 and `:help-echo' members." | |
2052 :button-prefix 'widget-link-prefix | 2100 :button-prefix 'widget-link-prefix |
2053 :button-suffix 'widget-link-suffix | 2101 :button-suffix 'widget-link-suffix |
2054 :help-echo "Follow the link." | 2102 :help-echo "Follow the link." |
2055 :format "%[%t%]") | 2103 :format "%[%t%]") |
2056 | 2104 |
2080 | 2128 |
2081 (defun widget-url-link-action (widget &optional event) | 2129 (defun widget-url-link-action (widget &optional event) |
2082 "Open the url specified by WIDGET." | 2130 "Open the url specified by WIDGET." |
2083 (if-fboundp 'browse-url | 2131 (if-fboundp 'browse-url |
2084 (browse-url (widget-value widget)) | 2132 (browse-url (widget-value widget)) |
2085 ;; #### Should subclass a 'missing-package error. | 2133 (error 'missing-package "Cannot browse URLs in this Emacs" 'browse-url))) |
2086 (error 'unimplemented | |
2087 "No `browse-url' package; cannot follow URLs in this XEmacs"))) | |
2088 | 2134 |
2089 ;;; The `function-link' Widget. | 2135 ;;; The `function-link' Widget. |
2090 | 2136 |
2091 (define-widget 'function-link 'link | 2137 (define-widget 'function-link 'link |
2092 "A link to an Emacs function." | 2138 "A link to an Emacs function." |
2180 (cons (widget-apply widget | 2226 (cons (widget-apply widget |
2181 :value-to-internal value) | 2227 :value-to-internal value) |
2182 0)) | 2228 0)) |
2183 (widget-get widget :prompt-history)))) | 2229 (widget-get widget :prompt-history)))) |
2184 | 2230 |
2185 (defvar widget-edit-functions nil) | 2231 ;; #### Should be named `widget-action-hooks'. |
2232 (defvar widget-edit-functions nil | |
2233 "Functions run on certain actions. | |
2234 | |
2235 Not a regular hook; each function should take a widget as an argument. | |
2236 The standard widget functions `widget-field-action', `widget-choice-action', | |
2237 and `widget-toggle-action' use `run-hook-with-args' to run these functions.") | |
2186 | 2238 |
2187 (defun widget-field-action (widget &optional event) | 2239 (defun widget-field-action (widget &optional event) |
2188 ;; Edit the value in the minibuffer. | 2240 ;; Edit the value in the minibuffer. |
2189 (let* ((invalid (widget-apply widget :validate)) | 2241 (let* ((invalid (widget-apply widget :validate)) |
2190 (prompt (concat (widget-apply widget :menu-tag-get) ": ")) | 2242 (prompt (concat (widget-apply widget :menu-tag-get) ": ")) |
2501 (widget-apply sibling :deactivate))))) | 2553 (widget-apply sibling :deactivate))))) |
2502 | 2554 |
2503 ;;; The `checklist' Widget. | 2555 ;;; The `checklist' Widget. |
2504 | 2556 |
2505 (define-widget 'checklist 'default | 2557 (define-widget 'checklist 'default |
2506 "A multiple choice widget." | 2558 "A set widget, selecting zero or more of many. |
2559 | |
2560 The parent of several `checkbox' widgets, one for each option." | |
2507 :convert-widget 'widget-types-convert-widget | 2561 :convert-widget 'widget-types-convert-widget |
2508 :format "%v" | 2562 :format "%v" |
2509 :offset 4 | 2563 :offset 4 |
2510 :entry-format "%b %v" | 2564 :entry-format "%b %v" |
2511 :menu-tag "checklist" | 2565 :menu-tag "checklist" |
2650 found)) | 2704 found)) |
2651 | 2705 |
2652 ;;; The `option' Widget | 2706 ;;; The `option' Widget |
2653 | 2707 |
2654 (define-widget 'option 'checklist | 2708 (define-widget 'option 'checklist |
2655 "An widget with an optional item." | 2709 "A widget presenting optional items for inline inclusion in a parent widget." |
2656 :inline t) | 2710 :inline t) |
2657 | 2711 |
2658 ;;; The `choice-item' Widget. | 2712 ;;; The `choice-item' Widget. |
2659 | 2713 |
2660 (define-widget 'choice-item 'item | 2714 (define-widget 'choice-item 'item |
2680 (widget-apply (widget-get widget :parent) :action widget event)) | 2734 (widget-apply (widget-get widget :parent) :action widget event)) |
2681 | 2735 |
2682 ;;; The `radio-button-choice' Widget. | 2736 ;;; The `radio-button-choice' Widget. |
2683 | 2737 |
2684 (define-widget 'radio-button-choice 'default | 2738 (define-widget 'radio-button-choice 'default |
2685 "Select one of multiple options." | 2739 "A set widget, selecting exactly one of many options. |
2740 | |
2741 The parent of several `radio-button' widgets, one for each option." | |
2686 :convert-widget 'widget-types-convert-widget | 2742 :convert-widget 'widget-types-convert-widget |
2687 :offset 4 | 2743 :offset 4 |
2688 :format "%v" | 2744 :format "%v" |
2689 :entry-format "%b %v" | 2745 :entry-format "%b %v" |
2690 :menu-tag "radio" | 2746 :menu-tag "radio" |
3262 (widget-value-set widget (widget-value widget))) | 3318 (widget-value-set widget (widget-value widget))) |
3263 | 3319 |
3264 | 3320 |
3265 ;;; The Sexp Widgets. | 3321 ;;; The Sexp Widgets. |
3266 | 3322 |
3323 (define-widget 'sexp 'editable-field | |
3324 "An arbitrary Lisp expression." | |
3325 :tag "Lisp expression" | |
3326 :format "%{%t%}: %v" | |
3327 :value nil | |
3328 :validate 'widget-sexp-validate | |
3329 :match (lambda (widget value) t) | |
3330 :value-to-internal 'widget-sexp-value-to-internal | |
3331 :value-to-external (lambda (widget value) (read value)) | |
3332 :prompt-history 'widget-sexp-prompt-value-history | |
3333 :prompt-value 'widget-sexp-prompt-value) | |
3334 | |
3335 (defun widget-sexp-value-to-internal (widget value) | |
3336 ;; Use cl-prettyprint for printer representation. | |
3337 (let ((pp (if (symbolp value) | |
3338 (prin1-to-string value) | |
3339 (widget-prettyprint-to-string value)))) | |
3340 (if (> (length pp) 40) | |
3341 (concat "\n" pp) | |
3342 pp))) | |
3343 | |
3344 (defun widget-sexp-validate (widget) | |
3345 ;; Valid if we can read the string and there is no junk left after it. | |
3346 (save-excursion | |
3347 (let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*")))) | |
3348 (erase-buffer) | |
3349 (insert (widget-apply widget :value-get)) | |
3350 (goto-char (point-min)) | |
3351 (condition-case data | |
3352 (let ((value (read buffer))) | |
3353 (if (eobp) | |
3354 (if (widget-apply widget :match value) | |
3355 nil | |
3356 (widget-put widget :error (widget-get widget :type-error)) | |
3357 widget) | |
3358 (widget-put widget | |
3359 :error (format "Junk at end of expression: %s" | |
3360 (buffer-substring (point) | |
3361 (point-max)))) | |
3362 widget)) | |
3363 (error (widget-put widget :error (error-message-string data)) | |
3364 widget))))) | |
3365 | |
3366 (defvar widget-sexp-prompt-value-history nil | |
3367 "History of input to `widget-sexp-prompt-value'.") | |
3368 | |
3369 (defun widget-sexp-prompt-value (widget prompt value unbound) | |
3370 ;; Read an arbitrary sexp. | |
3371 (let ((found (read-string prompt | |
3372 (if unbound nil (cons (prin1-to-string value) 0)) | |
3373 (widget-get widget :prompt-history)))) | |
3374 (save-excursion | |
3375 (let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*")))) | |
3376 (erase-buffer) | |
3377 (insert found) | |
3378 (goto-char (point-min)) | |
3379 (let ((answer (read buffer))) | |
3380 (unless (eobp) | |
3381 (signal 'error | |
3382 (list "Junk at end of expression" | |
3383 (buffer-substring (point) (point-max))))) | |
3384 answer))))) | |
3385 | |
3386 ;; Various constant sexps. | |
3387 | |
3267 (define-widget 'const 'item | 3388 (define-widget 'const 'item |
3268 "An immutable sexp." | 3389 "An immutable sexp." |
3269 :prompt-value 'widget-const-prompt-value | 3390 :prompt-value 'widget-const-prompt-value |
3270 :format "%t\n%d") | 3391 :format "%t\n%d") |
3271 | 3392 |
3400 (defvar widget-symbol-prompt-value-history nil | 3521 (defvar widget-symbol-prompt-value-history nil |
3401 "History of input to `widget-symbol-prompt-value'.") | 3522 "History of input to `widget-symbol-prompt-value'.") |
3402 | 3523 |
3403 (define-widget 'symbol 'editable-field | 3524 (define-widget 'symbol 'editable-field |
3404 "A Lisp symbol." | 3525 "A Lisp symbol." |
3405 :value nil | 3526 :value t |
3406 :tag "Symbol" | 3527 :tag "Symbol" |
3407 :format "%{%t%}: %v" | 3528 :format "%{%t%}: %v" |
3408 :match (lambda (widget value) (symbolp value)) | 3529 :match (lambda (widget value) (symbolp value)) |
3409 :complete-function 'lisp-complete-symbol | 3530 :complete-function 'lisp-complete-symbol |
3410 :prompt-internal 'widget-symbol-prompt-internal | 3531 :prompt-internal 'widget-symbol-prompt-internal |
3555 (buffer-substring (point) (point-max))))) | 3676 (buffer-substring (point) (point-max))))) |
3556 answer))))) | 3677 answer))))) |
3557 | 3678 |
3558 (define-widget 'restricted-sexp 'sexp | 3679 (define-widget 'restricted-sexp 'sexp |
3559 "A Lisp expression restricted to values that match. | 3680 "A Lisp expression restricted to values that match. |
3560 To use this type, you must define :match or :match-alternatives." | 3681 |
3682 Either the `:match' or the `:match-alternatives' property must be defined." | |
3561 :type-error "The specified value is not valid" | 3683 :type-error "The specified value is not valid" |
3562 :match 'widget-restricted-sexp-match | 3684 :match 'widget-restricted-sexp-match |
3563 :value-to-internal (lambda (widget value) | 3685 :value-to-internal (lambda (widget value) |
3564 (if (widget-apply widget :match value) | 3686 (if (widget-apply widget :match value) |
3565 (prin1-to-string value) | 3687 (prin1-to-string value) |
3603 "A character." | 3725 "A character." |
3604 :tag "Character" | 3726 :tag "Character" |
3605 :value ?\0 | 3727 :value ?\0 |
3606 :size 1 | 3728 :size 1 |
3607 :format "%{%t%}: %v" | 3729 :format "%{%t%}: %v" |
3730 ;; #### This is incorrect for Mule. | |
3608 :valid-regexp "\\`[\0-\377]\\'" | 3731 :valid-regexp "\\`[\0-\377]\\'" |
3609 :error "This field should contain a single character" | 3732 :error "This field should contain a single character" |
3610 :value-to-internal (lambda (widget value) | 3733 :value-to-internal (lambda (widget value) |
3611 (if (stringp value) | 3734 (if (stringp value) |
3612 value | 3735 value |
3617 value)) | 3740 value)) |
3618 :match (lambda (widget value) | 3741 :match (lambda (widget value) |
3619 (characterp value))) | 3742 (characterp value))) |
3620 | 3743 |
3621 (define-widget 'list 'group | 3744 (define-widget 'list 'group |
3622 "A Lisp list." | 3745 "A Lisp list of fixed length with fixed type for each element." |
3623 :tag "List" | 3746 :tag "List" |
3624 :format "%{%t%}:\n%v") | 3747 :format "%{%t%}:\n%v") |
3625 | 3748 |
3626 (define-widget 'vector 'group | 3749 (define-widget 'vector 'group |
3627 "A Lisp vector." | 3750 "A Lisp vector of fixed length with fixed type for each element." |
3628 :tag "Vector" | 3751 :tag "Vector" |
3629 :format "%{%t%}:\n%v" | 3752 :format "%{%t%}:\n%v" |
3630 :match 'widget-vector-match | 3753 :match 'widget-vector-match |
3631 :value-to-internal (lambda (widget value) (append value nil)) | 3754 :value-to-internal (lambda (widget value) (append value nil)) |
3632 :value-to-external (lambda (widget value) (vconcat value))) | 3755 :value-to-external (lambda (widget value) (vconcat value))) |
3790 (if current | 3913 (if current |
3791 (widget-prompt-value current prompt nil t) | 3914 (widget-prompt-value current prompt nil t) |
3792 value))) | 3915 value))) |
3793 | 3916 |
3794 (define-widget 'radio 'radio-button-choice | 3917 (define-widget 'radio 'radio-button-choice |
3795 "A union of several sexp types." | 3918 "A set widget, selecting exactly one from many. |
3919 | |
3920 The parent of several `radio-button' widgets, one for each option." | |
3796 :tag "Choice" | 3921 :tag "Choice" |
3797 :format "%{%t%}:\n%v" | 3922 :format "%{%t%}:\n%v" |
3798 :prompt-value 'widget-choice-prompt-value) | 3923 :prompt-value 'widget-choice-prompt-value) |
3799 | 3924 |
3800 (define-widget 'repeat 'editable-list | 3925 (define-widget 'repeat 'editable-list |