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