comparison lisp/w3/widget-edit.el @ 80:1ce6082ce73f r20-0b90

Import from CVS: tag r20-0b90
author cvs
date Mon, 13 Aug 2007 09:06:37 +0200
parents 131b0175ea99
children 6a378aca36af
comparison
equal deleted inserted replaced
79:5b0a5bbffab6 80:1ce6082ce73f
1 ;;; widget-edit.el --- Functions for creating and using widgets. 1 ;;; widget-edit.el --- Functions for creating and using widgets.
2 ;; 2 ;;
3 ;; Copyright (C) 1996 Free Software Foundation, Inc. 3 ;; Copyright (C) 1996 Free Software Foundation, Inc.
4 ;; 4 ;;
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6 ;; Keywords: help, extensions, faces, hypermedia 6 ;; Keywords: extensions
7 ;; Version: 0.4 7 ;; Version: 1.13
8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
8 9
9 ;;; Commentary: 10 ;;; Commentary:
10 ;; 11 ;;
11 ;; See `widget.el'. 12 ;; See `widget.el'.
12 13
13 ;;; Code: 14 ;;; Code:
14 15
15 (require 'widget) 16 (require 'widget)
16 (require 'cl) 17 (require 'cl)
18 (autoload 'pp-to-string "pp")
19 (autoload 'Info-goto-node "info")
20
21 (if (string-match "XEmacs" emacs-version)
22 ;; XEmacs spell `intangible' as `atomic'.
23 (defun widget-make-intangible (from to side)
24 "Make text between FROM and TO atomic with regard to movement.
25 Third argument should be `start-open' if it should be sticky to the rear,
26 and `end-open' if it should sticky to the front."
27 (require 'atomic-extents)
28 (let ((ext (make-extent from to)))
29 ;; XEmacs doesn't understant different kinds of read-only, so
30 ;; we have to use extents instead.
31 (put-text-property from to 'read-only nil)
32 (set-extent-property ext 'read-only t)
33 (set-extent-property ext 'start-open nil)
34 (set-extent-property ext 'end-open nil)
35 (set-extent-property ext side t)
36 (set-extent-property ext 'atomic t)))
37 (defun widget-make-intangible (from to size)
38 "Make text between FROM and TO intangible."
39 (put-text-property from to 'intangible 'front)))
40
41 ;; The following should go away when bundled with Emacs.
42 (eval-and-compile
43 (condition-case ()
44 (require 'custom)
45 (error nil))
46
47 (unless (and (featurep 'custom) (fboundp 'custom-declare-variable))
48 ;; We have the old custom-library, hack around it!
49 (defmacro defgroup (&rest args) nil)
50 (defmacro defcustom (&rest args) nil)
51 (defmacro defface (&rest args) nil)
52 (when (fboundp 'copy-face)
53 (copy-face 'default 'widget-documentation-face)
54 (copy-face 'bold 'widget-button-face)
55 (copy-face 'italic 'widget-field-face))
56 (defvar widget-mouse-face 'highlight)
57 (defvar widget-menu-max-size 40)))
17 58
18 ;;; Compatibility. 59 ;;; Compatibility.
19 60
20 (or (fboundp 'event-point) 61 (or (fboundp 'event-point)
21 ;; XEmacs function missing in Emacs. 62 ;; XEmacs function missing in Emacs.
24 or button-release event. If the event did not occur over a window, or did 65 or button-release event. If the event did not occur over a window, or did
25 not occur over text, then this returns nil. Otherwise, it returns an index 66 not occur over text, then this returns nil. Otherwise, it returns an index
26 into the buffer visible in the event's window." 67 into the buffer visible in the event's window."
27 (posn-point (event-start event)))) 68 (posn-point (event-start event))))
28 69
29 (or (fboundp 'set-keymap-parent)
30 ;; Xemacs function missing in Emacs.
31 ;; Definition stolen from `lucid.el'.
32 (defun set-keymap-parent (keymap new-parent)
33 (let ((tail keymap))
34 (while (and tail (cdr tail) (not (eq (car (cdr tail)) 'keymap)))
35 (setq tail (cdr tail)))
36 (if tail
37 (setcdr tail new-parent)))))
38
39 ;;; Customization. 70 ;;; Customization.
40 ;; 71
41 ;; These should be specified with the custom package. 72 (defgroup widgets nil
42 73 "Customization support for the Widget Library."
43 (defvar widget-button-face 'bold) 74 :link '(custom-manual "(widget)Top")
44 (defvar widget-mouse-face 'highlight) 75 :link '(url-link :tag "Development Page"
45 (defvar widget-field-face 'italic) 76 "http://www.dina.kvl.dk/~abraham/custom/")
46 77 :prefix "widget-"
47 (defvar widget-motion-hook nil 78 :group 'emacs)
48 "*Hook to be run after widget traversal (via `widget-forward|backward'). 79
49 The hooks will all be called with on argument - the widget that was just 80 (defface widget-documentation-face '((t ()))
50 selected.") 81 "Face used for documentation text."
82 :group 'widgets)
83
84 (defface widget-button-face '((t (:bold t)))
85 "Face used for widget buttons."
86 :group 'widgets)
87
88 (defcustom widget-mouse-face 'highlight
89 "Face used for widget buttons when the mouse is above them."
90 :type 'face
91 :group 'widgets)
92
93 (defface widget-field-face '((((type x)
94 (class grayscale color)
95 (background light))
96 (:background "light gray"))
97 (((type x)
98 (class grayscale color)
99 (background dark))
100 (:background "dark gray"))
101 (t
102 (:italic t)))
103 "Face used for editable fields."
104 :group 'widgets)
105
106 (defcustom widget-menu-max-size 40
107 "Largest number of items allowed in a popup-menu.
108 Larger menus are read through the minibuffer."
109 :type 'integer)
51 110
52 ;;; Utility functions. 111 ;;; Utility functions.
53 ;; 112 ;;
54 ;; These are not really widget specific. 113 ;; These are not really widget specific.
55 114
78 (defun widget-clear-undo () 137 (defun widget-clear-undo ()
79 "Clear all undo information." 138 "Clear all undo information."
80 (buffer-disable-undo (current-buffer)) 139 (buffer-disable-undo (current-buffer))
81 (buffer-enable-undo)) 140 (buffer-enable-undo))
82 141
142 (defun widget-choose (title items &optional event)
143 "Choose an item from a list.
144
145 First argument TITLE is the name of the list.
146 Second argument ITEMS is an alist (NAME . VALUE).
147 Optional third argument EVENT is an input event.
148
149 The user is asked to choose between each NAME from the items alist,
150 and the VALUE of the chosen element will be returned. If EVENT is a
151 mouse event, and the number of elements in items is less than
152 `widget-menu-max-size', a popup menu will be used, otherwise the
153 minibuffer."
154 (cond ((and (< (length items) widget-menu-max-size)
155 event (fboundp 'x-popup-menu) window-system)
156 ;; We are in Emacs-19, pressed by the mouse
157 (x-popup-menu event
158 (list title (cons "" items))))
159 ((and (< (length items) widget-menu-max-size)
160 event (fboundp 'popup-menu) window-system)
161 ;; We are in XEmacs, pressed by the mouse
162 (let ((val (get-popup-menu-response
163 (cons ""
164 (mapcar
165 (function
166 (lambda (x)
167 (vector (car x) (list (car x)) t)))
168 items)))))
169 (setq val (and val
170 (listp (event-object val))
171 (stringp (car-safe (event-object val)))
172 (car (event-object val))))
173 (cdr (assoc val items))))
174 (t
175 (cdr (assoc (completing-read (concat title ": ")
176 items nil t)
177 items)))))
178
83 ;;; Widget text specifications. 179 ;;; Widget text specifications.
84 ;; 180 ;;
85 ;; These functions are for specifying text properties. 181 ;; These functions are for specifying text properties.
86 182
87 (defun widget-specify-none (from to) 183 (defun widget-specify-none (from to)
90 186
91 (defun widget-specify-text (from to) 187 (defun widget-specify-text (from to)
92 ;; Default properties. 188 ;; Default properties.
93 (add-text-properties from to (list 'read-only t 189 (add-text-properties from to (list 'read-only t
94 'front-sticky t 190 'front-sticky t
191 'start-open t
192 'end-open t
95 'rear-nonsticky nil))) 193 'rear-nonsticky nil)))
96 194
97 (defun widget-specify-field (widget from to) 195 (defun widget-specify-field (widget from to)
98 ;; Specify editable button for WIDGET between FROM and TO. 196 ;; Specify editable button for WIDGET between FROM and TO.
99 (widget-specify-field-update widget from to) 197 (widget-specify-field-update widget from to)
100 ;; Make it possible to edit both end of the field. 198
199 ;; Make it possible to edit the front end of the field.
101 (add-text-properties (1- from) from (list 'rear-nonsticky t 200 (add-text-properties (1- from) from (list 'rear-nonsticky t
102 'end-open t 201 'end-open t
103 'invisible t)) 202 'invisible t))
104 (add-text-properties to (1+ to) (list 'font-sticky nil 203 (when (or (string-match "\\(.\\|\n\\)%v" (widget-get widget :format))
105 'start-open t))) 204 (widget-get widget :hide-front-space))
205 ;; WARNING: This is going to lose horrible if the character just
206 ;; before the field can be modified (e.g. if it belongs to a
207 ;; choice widget). We try to compensate by checking the format
208 ;; string, and hope the user hasn't changed the :create method.
209 (widget-make-intangible (- from 2) from 'end-open))
210
211 ;; Make it possible to edit back end of the field.
212 (add-text-properties to (1+ to) (list 'front-sticky nil
213 'read-only t
214 'start-open t))
215
216 (cond ((widget-get widget :size)
217 (put-text-property to (1+ to) 'invisible t)
218 (when (or (string-match "%v\\(.\\|\n\\)" (widget-get widget :format))
219 (widget-get widget :hide-rear-space))
220 ;; WARNING: This is going to lose horrible if the character just
221 ;; after the field can be modified (e.g. if it belongs to a
222 ;; choice widget). We try to compensate by checking the format
223 ;; string, and hope the user hasn't changed the :create method.
224 (widget-make-intangible to (+ to 2) 'start-open)))
225 ((string-match "XEmacs" emacs-version)
226 ;; XEmacs does not allow you to insert before a read-only
227 ;; character, even if it is start.open.
228 ;; XEmacs does allow you to delete an read-only extent, so
229 ;; making the terminating newline read only doesn't help.
230 ;; I tried putting an invisible intangible read-only space
231 ;; before the newline, which gave really weird effects.
232 ;; So for now, we just have trust the user not to delete the
233 ;; newline.
234 (put-text-property to (1+ to) 'read-only nil))))
106 235
107 (defun widget-specify-field-update (widget from to) 236 (defun widget-specify-field-update (widget from to)
108 ;; Specify editable button for WIDGET between FROM and TO. 237 ;; Specify editable button for WIDGET between FROM and TO.
109 (let ((map (widget-get widget :keymap)) 238 (let ((map (widget-get widget :keymap))
110 (face (or (widget-get widget :value-face) 239 (face (or (widget-get widget :value-face)
111 widget-field-face))) 240 'widget-field-face)))
112 (add-text-properties from to (list 'field widget 241 (set-text-properties from to (list 'field widget
113 'read-only nil 242 'read-only nil
243 'keymap map
114 'local-map map 244 'local-map map
115 'keymap map 245 'face face))
116 'face widget-field-face)))) 246 (unless (widget-get widget :size)
247 (put-text-property to (1+ to) 'face face))))
117 248
118 (defun widget-specify-button (widget from to) 249 (defun widget-specify-button (widget from to)
119 ;; Specify button for WIDGET between FROM and TO. 250 ;; Specify button for WIDGET between FROM and TO.
120 (let ((face (or (widget-get widget :button-face) 251 (let ((face (widget-apply widget :button-face-get)))
121 widget-button-face)))
122 (add-text-properties from to (list 'button widget 252 (add-text-properties from to (list 'button widget
123 'mouse-face widget-mouse-face 253 'mouse-face widget-mouse-face
254 'start-open t
255 'end-open t
124 'face face)))) 256 'face face))))
125 257
126 (defun widget-specify-doc (widget from to) 258 (defun widget-specify-doc (widget from to)
127 ;; Specify documentation for WIDGET between FROM and TO. 259 ;; Specify documentation for WIDGET between FROM and TO.
128 (put-text-property from to 'widget-doc widget)) 260 (add-text-properties from to (list 'widget-doc widget
129 261 'face 'widget-documentation-face)))
130 262
131 (defmacro widget-specify-insert (&rest form) 263 (defmacro widget-specify-insert (&rest form)
132 ;; Execute FORM without inheriting any text properties. 264 ;; Execute FORM without inheriting any text properties.
133 (` 265 `(save-restriction
134 (save-restriction
135 (let ((inhibit-read-only t) 266 (let ((inhibit-read-only t)
136 result 267 result
137 after-change-functions) 268 after-change-functions)
138 (insert "<>") 269 (insert "<>")
139 (narrow-to-region (- (point) 2) (point)) 270 (narrow-to-region (- (point) 2) (point))
140 (widget-specify-none (point-min) (point-max)) 271 (widget-specify-none (point-min) (point-max))
141 (goto-char (1+ (point-min))) 272 (goto-char (1+ (point-min)))
142 (setq result (progn (,@ form))) 273 (setq result (progn ,@form))
143 (delete-region (point-min) (1+ (point-min))) 274 (delete-region (point-min) (1+ (point-min)))
144 (delete-region (1- (point-max)) (point-max)) 275 (delete-region (1- (point-max)) (point-max))
145 (goto-char (point-max)) 276 (goto-char (point-max))
146 result)))) 277 result)))
147 278
148 ;;; Widget Properties. 279 ;;; Widget Properties.
149 280
150 (defun widget-put (widget property value) 281 (defun widget-put (widget property value)
151 "In WIDGET set PROPERTY to VALUE. 282 "In WIDGET set PROPERTY to VALUE.
184 "Set the current value of WIDGET to VALUE." 315 "Set the current value of WIDGET to VALUE."
185 (widget-apply widget 316 (widget-apply widget
186 :value-set (widget-apply widget 317 :value-set (widget-apply widget
187 :value-to-internal value))) 318 :value-to-internal value)))
188 319
189 (defun widget-match-inline (widget values) 320 (defun widget-match-inline (widget vals)
190 ;; Match the head of values. 321 ;; In WIDGET, match the start of VALS.
191 (cond ((widget-get widget :inline) 322 (cond ((widget-get widget :inline)
192 (widget-apply widget :match-inline values)) 323 (widget-apply widget :match-inline vals))
193 ((widget-apply widget :match (car values)) 324 ((and vals
194 (cons (list (car values)) (cdr values))) 325 (widget-apply widget :match (car vals)))
326 (cons (list (car vals)) (cdr vals)))
195 (t nil))) 327 (t nil)))
196 328
197 ;;; Creating Widgets. 329 ;;; Creating Widgets.
198 330
331 ;;;###autoload
199 (defun widget-create (type &rest args) 332 (defun widget-create (type &rest args)
200 "Create widget of TYPE. 333 "Create widget of TYPE.
201 The optional ARGS are additional keyword arguments." 334 The optional ARGS are additional keyword arguments."
202 (let ((widget (apply 'widget-convert type args))) 335 (let ((widget (apply 'widget-convert type args)))
203 (widget-apply widget :create) 336 (widget-apply widget :create)
204 widget)) 337 widget))
205 338
339 (defun widget-create-child-and-convert (parent type &rest args)
340 "As part of the widget PARENT, create a child widget TYPE.
341 The child is converted, using the keyword arguments ARGS."
342 (let ((widget (apply 'widget-convert type args)))
343 (widget-put widget :parent parent)
344 (unless (widget-get widget :indent)
345 (widget-put widget :indent (+ (or (widget-get parent :indent) 0)
346 (or (widget-get widget :extra-offset) 0)
347 (widget-get parent :offset))))
348 (widget-apply widget :create)
349 widget))
350
351 (defun widget-create-child (parent type)
352 "Create widget of TYPE."
353 (let ((widget (copy-list type)))
354 (widget-put widget :parent parent)
355 (unless (widget-get widget :indent)
356 (widget-put widget :indent (+ (or (widget-get parent :indent) 0)
357 (or (widget-get widget :extra-offset) 0)
358 (widget-get parent :offset))))
359 (widget-apply widget :create)
360 widget))
361
362 (defun widget-create-child-value (parent type value)
363 "Create widget of TYPE with value VALUE."
364 (let ((widget (copy-list type)))
365 (widget-put widget :value (widget-apply widget :value-to-internal value))
366 (widget-put widget :parent parent)
367 (unless (widget-get widget :indent)
368 (widget-put widget :indent (+ (or (widget-get parent :indent) 0)
369 (or (widget-get widget :extra-offset) 0)
370 (widget-get parent :offset))))
371 (widget-apply widget :create)
372 widget))
373
374 ;;;###autoload
206 (defun widget-delete (widget) 375 (defun widget-delete (widget)
207 "Delete WIDGET." 376 "Delete WIDGET."
208 (widget-apply widget :delete)) 377 (widget-apply widget :delete))
209 378
210 (defun widget-convert (type &rest args) 379 (defun widget-convert (type &rest args)
230 (widget-put widget :args args) 399 (widget-put widget :args args)
231 (setq args nil)))) 400 (setq args nil))))
232 ;; Then Convert the widget. 401 ;; Then Convert the widget.
233 (setq type widget) 402 (setq type widget)
234 (while type 403 (while type
235 (let ((convert-widget (widget-get type :convert-widget))) 404 (let ((convert-widget (plist-get (cdr type) :convert-widget)))
236 (if convert-widget 405 (if convert-widget
237 (setq widget (funcall convert-widget widget)))) 406 (setq widget (funcall convert-widget widget))))
238 (setq type (get (car type) 'widget-type))) 407 (setq type (get (car type) 'widget-type)))
239 ;; Finally set the keyword args. 408 ;; Finally set the keyword args.
240 (while keys 409 (while keys
242 (if (and (symbolp next) (eq (aref (symbol-name next) 0) ?:)) 411 (if (and (symbolp next) (eq (aref (symbol-name next) 0) ?:))
243 (progn 412 (progn
244 (widget-put widget next (nth 1 keys)) 413 (widget-put widget next (nth 1 keys))
245 (setq keys (nthcdr 2 keys))) 414 (setq keys (nthcdr 2 keys)))
246 (setq keys nil)))) 415 (setq keys nil))))
416 ;; Convert the :value to internal format.
417 (if (widget-member widget :value)
418 (let ((value (widget-get widget :value)))
419 (widget-put widget
420 :value (widget-apply widget :value-to-internal value))))
247 ;; Return the newly create widget. 421 ;; Return the newly create widget.
248 widget)) 422 widget))
249 423
250 (defun widget-insert (&rest args) 424 (defun widget-insert (&rest args)
251 "Call `insert' with ARGS and make the text read only." 425 "Call `insert' with ARGS and make the text read only."
266 (setq widget-keymap (make-sparse-keymap)) 440 (setq widget-keymap (make-sparse-keymap))
267 (set-keymap-parent widget-keymap global-map) 441 (set-keymap-parent widget-keymap global-map)
268 (define-key widget-keymap "\t" 'widget-forward) 442 (define-key widget-keymap "\t" 'widget-forward)
269 (define-key widget-keymap "\M-\t" 'widget-backward) 443 (define-key widget-keymap "\M-\t" 'widget-backward)
270 (define-key widget-keymap [(shift tab)] 'widget-backward) 444 (define-key widget-keymap [(shift tab)] 'widget-backward)
445 (define-key widget-keymap [(shift tab)] 'widget-backward)
446 (define-key widget-keymap [backtab] 'widget-backward)
271 (if (string-match "XEmacs" (emacs-version)) 447 (if (string-match "XEmacs" (emacs-version))
272 (define-key widget-keymap [button2] 'widget-button-click) 448 (define-key widget-keymap [button2] 'widget-button-click)
449 (define-key widget-keymap [menu-bar] 'nil)
273 (define-key widget-keymap [mouse-2] 'widget-button-click)) 450 (define-key widget-keymap [mouse-2] 'widget-button-click))
274 (define-key widget-keymap "\C-m" 'widget-button-press)) 451 (define-key widget-keymap "\C-m" 'widget-button-press))
275 452
276 (defvar widget-global-map global-map 453 (defvar widget-global-map global-map
277 "Keymap used for events the widget does not handle themselves.") 454 "Keymap used for events the widget does not handle themselves.")
354 (field (previous-single-property-change (point) 'field))) 531 (field (previous-single-property-change (point) 'field)))
355 (cond ((and button field) 532 (cond ((and button field)
356 (goto-char (max button field))) 533 (goto-char (max button field)))
357 (button (goto-char button)) 534 (button (goto-char button))
358 (field (goto-char field))))) 535 (field (goto-char field)))))
359 (run-hook-with-args 'widget-motion-hook (or 536 (widget-echo-help (point)))
360 (get-text-property (point) 'button)
361 (get-text-property (point) 'field)))
362 )
363 537
364 (defun widget-backward (arg) 538 (defun widget-backward (arg)
365 "Move point to the previous field or button. 539 "Move point to the previous field or button.
366 With optional ARG, move across that many fields." 540 With optional ARG, move across that many fields."
367 (interactive "p") 541 (interactive "p")
378 (make-variable-buffer-local 'widget-field-list) 552 (make-variable-buffer-local 'widget-field-list)
379 553
380 (defun widget-setup () 554 (defun widget-setup ()
381 "Setup current buffer so editing string widgets works." 555 "Setup current buffer so editing string widgets works."
382 (let ((inhibit-read-only t) 556 (let ((inhibit-read-only t)
557 (after-change-functions nil)
383 field) 558 field)
384 (while widget-field-new 559 (while widget-field-new
385 (setq field (car widget-field-new) 560 (setq field (car widget-field-new)
386 widget-field-new (cdr widget-field-new) 561 widget-field-new (cdr widget-field-new)
387 widget-field-list (cons field widget-field-list)) 562 widget-field-list (cons field widget-field-list))
428 (condition-case nil 603 (condition-case nil
429 (let ((field (widget-field-find from)) 604 (let ((field (widget-field-find from))
430 (inhibit-read-only t)) 605 (inhibit-read-only t))
431 (cond ((null field)) 606 (cond ((null field))
432 ((not (eq field (widget-field-find to))) 607 ((not (eq field (widget-field-find to)))
608 (debug)
433 (message "Error: `widget-after-change' called on two fields")) 609 (message "Error: `widget-after-change' called on two fields"))
434 (t 610 (t
435 (let ((size (widget-get field :size))) 611 (let ((size (widget-get field :size)))
436 (if size 612 (if size
437 (let ((begin (1+ (widget-get field :value-from))) 613 (let ((begin (1+ (widget-get field :value-from)))
439 (widget-specify-field-update field begin end) 615 (widget-specify-field-update field begin end)
440 (cond ((< (- end begin) size) 616 (cond ((< (- end begin) size)
441 ;; Field too small. 617 ;; Field too small.
442 (save-excursion 618 (save-excursion
443 (goto-char end) 619 (goto-char end)
444 (insert-char ?\ (- (+ begin size) end)))) 620 (insert-char ?\ (- (+ begin size) end))
621 (widget-specify-field-update field
622 begin
623 (+ begin size))))
445 ((> (- end begin) size) 624 ((> (- end begin) size)
446 ;; Field too large and 625 ;; Field too large and
447 (if (or (< (point) (+ begin size)) 626 (if (or (< (point) (+ begin size))
448 (> (point) end)) 627 (> (point) end))
449 ;; Point is outside extra space. 628 ;; Point is outside extra space.
457 (delete-backward-char 1)))))) 636 (delete-backward-char 1))))))
458 (widget-specify-field-update field from to))) 637 (widget-specify-field-update field from to)))
459 (widget-apply field :notify field)))) 638 (widget-apply field :notify field))))
460 (error (debug)))) 639 (error (debug))))
461 640
641 ;;; Widget Functions
642 ;;
643 ;; These functions are used in the definition of multiple widgets.
644
645 (defun widget-children-value-delete (widget)
646 "Delete all :children and :buttons in WIDGET."
647 (mapcar 'widget-delete (widget-get widget :children))
648 (widget-put widget :children nil)
649 (mapcar 'widget-delete (widget-get widget :buttons))
650 (widget-put widget :buttons nil))
651
652 (defun widget-types-convert-widget (widget)
653 "Convert :args as widget types in WIDGET."
654 (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args)))
655 widget)
656
462 ;;; The `default' Widget. 657 ;;; The `default' Widget.
463 658
464 (define-widget 'default nil 659 (define-widget 'default nil
465 "Basic widget other widgets are derived from." 660 "Basic widget other widgets are derived from."
466 :value-to-internal (lambda (widget value) value) 661 :value-to-internal (lambda (widget value) value)
467 :value-to-external (lambda (widget value) value) 662 :value-to-external (lambda (widget value) value)
468 :create 'widget-default-create 663 :create 'widget-default-create
664 :indent nil
665 :offset 0
469 :format-handler 'widget-default-format-handler 666 :format-handler 'widget-default-format-handler
667 :button-face-get 'widget-default-button-face-get
470 :delete 'widget-default-delete 668 :delete 'widget-default-delete
471 :value-set 'widget-default-value-set 669 :value-set 'widget-default-value-set
472 :value-inline 'widget-default-value-inline 670 :value-inline 'widget-default-value-inline
473 :menu-tag-get 'widget-default-menu-tag-get 671 :menu-tag-get 'widget-default-menu-tag-get
474 :validate (lambda (widget) t) 672 :validate (lambda (widget) nil)
475 :action 'widget-default-action 673 :action 'widget-default-action
476 :notify 'widget-default-notify) 674 :notify 'widget-default-notify)
477 675
478 (defun widget-default-create (widget) 676 (defun widget-default-create (widget)
479 "Create WIDGET at point in the current buffer." 677 "Create WIDGET at point in the current buffer."
494 (insert "%")) 692 (insert "%"))
495 ((eq escape ?\[) 693 ((eq escape ?\[)
496 (setq button-begin (point))) 694 (setq button-begin (point)))
497 ((eq escape ?\]) 695 ((eq escape ?\])
498 (setq button-end (point))) 696 (setq button-end (point)))
697 ((eq escape ?n)
698 (when (widget-get widget :indent)
699 (insert "\n")
700 (insert-char ? (widget-get widget :indent))))
499 ((eq escape ?t) 701 ((eq escape ?t)
500 (if tag 702 (if tag
501 (insert tag) 703 (insert tag)
502 (let ((standard-output (current-buffer))) 704 (let ((standard-output (current-buffer)))
503 (princ (widget-get widget :value))))) 705 (princ (widget-get widget :value)))))
530 (set-marker-insertion-type to nil) 732 (set-marker-insertion-type to nil)
531 (widget-put widget :from from) 733 (widget-put widget :from from)
532 (widget-put widget :to to)))) 734 (widget-put widget :to to))))
533 735
534 (defun widget-default-format-handler (widget escape) 736 (defun widget-default-format-handler (widget escape)
535 ;; By default unknown escapes are errors. 737 ;; We recognize the %h escape by default.
536 (error "Unknown escape `%c'" escape)) 738 (let* ((buttons (widget-get widget :buttons))
739 (doc-property (widget-get widget :documentation-property))
740 (doc-try (cond ((widget-get widget :doc))
741 ((symbolp doc-property)
742 (documentation-property (widget-get widget :value)
743 doc-property))
744 (t
745 (funcall doc-property (widget-get widget :value)))))
746 (doc-text (and (stringp doc-try)
747 (> (length doc-try) 1)
748 doc-try)))
749 (cond ((eq escape ?h)
750 (when doc-text
751 (and (eq (preceding-char) ?\n)
752 (widget-get widget :indent)
753 (insert-char ? (widget-get widget :indent)))
754 ;; The `*' in the beginning is redundant.
755 (when (eq (aref doc-text 0) ?*)
756 (setq doc-text (substring doc-text 1)))
757 ;; Get rid of trailing newlines.
758 (when (string-match "\n+\\'" doc-text)
759 (setq doc-text (substring doc-text 0 (match-beginning 0))))
760 (push (if (string-match "\n." doc-text)
761 ;; Allow multiline doc to be hiden.
762 (widget-create-child-and-convert
763 widget 'widget-help
764 :doc (progn
765 (string-match "\\`.*" doc-text)
766 (match-string 0 doc-text))
767 :widget-doc doc-text
768 "?")
769 ;; A single line is just inserted.
770 (widget-create-child-and-convert
771 widget 'item :format "%d" :doc doc-text nil))
772 buttons)))
773 (t
774 (error "Unknown escape `%c'" escape)))
775 (widget-put widget :buttons buttons)))
776
777 (defun widget-default-button-face-get (widget)
778 ;; Use :button-face or widget-button-face
779 (or (widget-get widget :button-face) 'widget-button-face))
537 780
538 (defun widget-default-delete (widget) 781 (defun widget-default-delete (widget)
539 ;; Remove widget from the buffer. 782 ;; Remove widget from the buffer.
540 (let ((from (widget-get widget :from)) 783 (let ((from (widget-get widget :from))
541 (to (widget-get widget :to)) 784 (to (widget-get widget :to))
588 :match-inline 'widget-item-match-inline 831 :match-inline 'widget-item-match-inline
589 :action 'widget-item-action 832 :action 'widget-item-action
590 :format "%t\n") 833 :format "%t\n")
591 834
592 (defun widget-item-convert-widget (widget) 835 (defun widget-item-convert-widget (widget)
593 ;; Initialize :value and :tag from :args in WIDGET. 836 ;; Initialize :value from :args in WIDGET.
594 (let ((args (widget-get widget :args))) 837 (let ((args (widget-get widget :args)))
595 (when args 838 (when args
596 (widget-put widget :value (car args)) 839 (widget-put widget :value (widget-apply widget
840 :value-to-internal (car args)))
597 (widget-put widget :args nil))) 841 (widget-put widget :args nil)))
598 widget) 842 widget)
599 843
600 (defun widget-item-value-create (widget) 844 (defun widget-item-value-create (widget)
601 ;; Insert the printed representation of the value. 845 ;; Insert the printed representation of the value.
621 865
622 (defun widget-item-value-get (widget) 866 (defun widget-item-value-get (widget)
623 ;; Items are simple. 867 ;; Items are simple.
624 (widget-get widget :value)) 868 (widget-get widget :value))
625 869
626 ;;; The `push' Widget. 870 ;;; The `push-button' Widget.
627 871
628 (define-widget 'push 'item 872 (define-widget 'push-button 'item
629 "A pushable button." 873 "A pushable button."
630 :format "%[[%t]%]") 874 :format "%[[%t]%]")
631 875
632 ;;; The `link' Widget. 876 ;;; The `link' Widget.
633 877
634 (define-widget 'link 'item 878 (define-widget 'link 'item
635 "An embedded link." 879 "An embedded link."
636 :format "%[_%t_%]") 880 :format "%[_%t_%]")
637 881
638 ;;; The `field' Widget. 882 ;;; The `info-link' Widget.
639 883
640 (define-widget 'field 'default 884 (define-widget 'info-link 'link
885 "A link to an info file."
886 :action 'widget-info-link-action)
887
888 (defun widget-info-link-action (widget &optional event)
889 "Open the info node specified by WIDGET."
890 (Info-goto-node (widget-value widget)))
891
892 ;;; The `url-link' Widget.
893
894 (define-widget 'url-link 'link
895 "A link to an www page."
896 :action 'widget-url-link-action)
897
898 (defun widget-url-link-action (widget &optional event)
899 "Open the url specified by WIDGET."
900 (require 'browse-url)
901 (funcall browse-url-browser-function (widget-value widget)))
902
903 ;;; The `editable-field' Widget.
904
905 (define-widget 'editable-field 'default
641 "An editable text field." 906 "An editable text field."
642 :convert-widget 'widget-item-convert-widget 907 :convert-widget 'widget-item-convert-widget
643 :format "%v" 908 :format "%v"
644 :value "" 909 :value ""
645 :tag "field" 910 :action 'widget-field-action
646 :value-create 'widget-field-value-create 911 :value-create 'widget-field-value-create
647 :value-delete 'widget-field-value-delete 912 :value-delete 'widget-field-value-delete
648 :value-get 'widget-field-value-get 913 :value-get 'widget-field-value-get
649 :match 'widget-field-match) 914 :match 'widget-field-match)
915
916 ;; History of field minibuffer edits.
917 (defvar widget-field-history nil)
918
919 (defun widget-field-action (widget &optional event)
920 ;; Edit the value in the minibuffer.
921 (let ((tag (widget-apply widget :menu-tag-get))
922 (invalid (widget-apply widget :validate)))
923 (when invalid
924 (error (widget-get invalid :error)))
925 (widget-value-set widget
926 (widget-apply widget
927 :value-to-external
928 (read-string (concat tag ": ")
929 (widget-apply
930 widget
931 :value-to-internal
932 (widget-value widget))
933 'widget-field-history)))
934 (widget-apply widget :notify widget event)
935 (widget-setup)))
650 936
651 (defun widget-field-value-create (widget) 937 (defun widget-field-value-create (widget)
652 ;; Create an editable text field. 938 ;; Create an editable text field.
653 (insert " ") 939 (insert " ")
654 (let ((size (widget-get widget :size)) 940 (let ((size (widget-get widget :size))
655 (value (widget-get widget :value)) 941 (value (widget-get widget :value))
656 (from (point))) 942 (from (point)))
657 (if (null size) 943 (insert value)
658 (insert value) 944 (and size
659 (insert value) 945 (< (length value) size)
660 (if (< (length value) size) 946 (insert-char ?\ (- size (length value))))
661 (insert-char ?\ (- size (length value)))))
662 (unless (memq widget widget-field-list) 947 (unless (memq widget widget-field-list)
663 (setq widget-field-new (cons widget widget-field-new))) 948 (setq widget-field-new (cons widget widget-field-new)))
664 (widget-put widget :value-from (copy-marker from))
665 (set-marker-insertion-type (widget-get widget :value-from) t)
666 (widget-put widget :value-to (copy-marker (point))) 949 (widget-put widget :value-to (copy-marker (point)))
667 (set-marker-insertion-type (widget-get widget :value-to) nil) 950 (set-marker-insertion-type (widget-get widget :value-to) nil)
668 (if (null size) 951 (if (null size)
669 (insert ?\n) 952 (insert ?\n)
670 (insert ?\ )))) 953 (insert ?\ ))
954 (widget-put widget :value-from (copy-marker from))
955 (set-marker-insertion-type (widget-get widget :value-from) t)))
671 956
672 (defun widget-field-value-delete (widget) 957 (defun widget-field-value-delete (widget)
673 ;; Remove the widget from the list of active editing fields. 958 ;; Remove the widget from the list of active editing fields.
674 (setq widget-field-list (delq widget widget-field-list)) 959 (setq widget-field-list (delq widget widget-field-list))
675 (set-marker (widget-get widget :value-from) nil) 960 (set-marker (widget-get widget :value-from) nil)
676 (set-marker (widget-get widget :value-to) nil)) 961 (set-marker (widget-get widget :value-to) nil))
677 962
678 (defun widget-field-value-get (widget) 963 (defun widget-field-value-get (widget)
679 ;; Return current text in editing field. 964 ;; Return current text in editing field.
680 (let ((from (widget-get widget :value-from)) 965 (let ((from (widget-get widget :value-from))
681 (to (widget-get widget :value-to))) 966 (to (widget-get widget :value-to))
967 (size (widget-get widget :size))
968 (old (current-buffer)))
682 (if (and from to) 969 (if (and from to)
683 (progn 970 (progn
971 (set-buffer (marker-buffer from))
684 (setq from (1+ from) 972 (setq from (1+ from)
685 to (1- to)) 973 to (1- to))
686 (while (and (> to from) 974 (while (and size
975 (not (zerop size))
976 (> to from)
687 (eq (char-after (1- to)) ?\ )) 977 (eq (char-after (1- to)) ?\ ))
688 (setq to (1- to))) 978 (setq to (1- to)))
689 (buffer-substring-no-properties from to)) 979 (prog1 (buffer-substring-no-properties from to)
980 (set-buffer old)))
690 (widget-get widget :value)))) 981 (widget-get widget :value))))
691 982
692 (defun widget-field-match (widget value) 983 (defun widget-field-match (widget value)
693 ;; Match any string. 984 ;; Match any string.
694 (stringp value)) 985 (stringp value))
695 986
696 ;;; The `choice' Widget. 987 ;;; The `text' Widget.
697 988
698 (define-widget 'choice 'default 989 (define-widget 'text 'editable-field
990 "A multiline text area.")
991
992 ;;; The `menu-choice' Widget.
993
994 (define-widget 'menu-choice 'default
699 "A menu of options." 995 "A menu of options."
700 :convert-widget 'widget-choice-convert-widget 996 :convert-widget 'widget-types-convert-widget
701 :format "%[%t%]: %v" 997 :format "%[%t%]: %v"
998 :case-fold t
702 :tag "choice" 999 :tag "choice"
703 :inline t 1000 :void '(item :format "invalid (%t)\n")
704 :void '(item "void")
705 :value-create 'widget-choice-value-create 1001 :value-create 'widget-choice-value-create
706 :value-delete 'widget-radio-value-delete 1002 :value-delete 'widget-children-value-delete
707 :value-get 'widget-choice-value-get 1003 :value-get 'widget-choice-value-get
708 :value-inline 'widget-choice-value-inline 1004 :value-inline 'widget-choice-value-inline
709 :action 'widget-choice-action 1005 :action 'widget-choice-action
710 :error "Make a choice" 1006 :error "Make a choice"
711 :validate 'widget-choice-validate 1007 :validate 'widget-choice-validate
712 :match 'widget-choice-match 1008 :match 'widget-choice-match
713 :match-inline 'widget-choice-match-inline) 1009 :match-inline 'widget-choice-match-inline)
714
715 (defun widget-choice-convert-widget (widget)
716 ;; Expand type args into widget objects.
717 (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args)))
718 widget)
719 1010
720 (defun widget-choice-value-create (widget) 1011 (defun widget-choice-value-create (widget)
721 ;; Insert the first choice that matches the value. 1012 ;; Insert the first choice that matches the value.
722 (let ((value (widget-get widget :value)) 1013 (let ((value (widget-get widget :value))
723 (args (widget-get widget :args)) 1014 (args (widget-get widget :args))
724 current) 1015 current)
725 (while args 1016 (while args
726 (setq current (car args) 1017 (setq current (car args)
727 args (cdr args)) 1018 args (cdr args))
728 (when (widget-apply current :match value) 1019 (when (widget-apply current :match value)
729 (widget-put widget :children (list (widget-create current 1020 (widget-put widget :children (list (widget-create-child-value
730 :parent widget 1021 widget current value)))
731 :value value)))
732 (widget-put widget :choice current) 1022 (widget-put widget :choice current)
733 (setq args nil 1023 (setq args nil
734 current nil))) 1024 current nil)))
735 (when current 1025 (when current
736 (let ((void (widget-get widget :void))) 1026 (let ((void (widget-get widget :void)))
737 (widget-put widget :children (list (widget-create void 1027 (widget-put widget :children (list (widget-create-child-and-convert
738 :parent widget 1028 widget void :value value)))
739 :value value)))
740 (widget-put widget :choice void))))) 1029 (widget-put widget :choice void)))))
741 1030
742 (defun widget-choice-value-get (widget) 1031 (defun widget-choice-value-get (widget)
743 ;; Get value of the child widget. 1032 ;; Get value of the child widget.
744 (widget-value (car (widget-get widget :children)))) 1033 (widget-value (car (widget-get widget :children))))
750 (defun widget-choice-action (widget &optional event) 1039 (defun widget-choice-action (widget &optional event)
751 ;; Make a choice. 1040 ;; Make a choice.
752 (let ((args (widget-get widget :args)) 1041 (let ((args (widget-get widget :args))
753 (old (widget-get widget :choice)) 1042 (old (widget-get widget :choice))
754 (tag (widget-apply widget :menu-tag-get)) 1043 (tag (widget-apply widget :menu-tag-get))
1044 (completion-ignore-case (widget-get widget :case-fold))
755 current choices) 1045 current choices)
1046 ;; Remember old value.
1047 (if (and old (not (widget-apply widget :validate)))
1048 (let* ((external (widget-value widget))
1049 (internal (widget-apply old :value-to-internal external)))
1050 (widget-put old :value internal)))
1051 ;; Find new choice.
756 (setq current 1052 (setq current
757 (cond ((= (length args) 0) 1053 (cond ((= (length args) 0)
758 nil) 1054 nil)
759 ((= (length args) 1) 1055 ((= (length args) 1)
760 (nth 0 args)) 1056 (nth 0 args))
769 args (cdr args)) 1065 args (cdr args))
770 (setq choices 1066 (setq choices
771 (cons (cons (widget-apply current :menu-tag-get) 1067 (cons (cons (widget-apply current :menu-tag-get)
772 current) 1068 current)
773 choices))) 1069 choices)))
774 (cond 1070 (widget-choose tag (reverse choices) event))))
775 ((and event (fboundp 'x-popup-menu) window-system)
776 ;; We are in Emacs-19, pressed by the mouse
777 (x-popup-menu event
778 (list tag (cons "" (reverse choices)))))
779 ((and event (fboundp 'popup-menu) window-system)
780 ;; We are in XEmacs, pressed by the mouse
781 (let ((val (get-popup-menu-response
782 (cons ""
783 (mapcar
784 (function
785 (lambda (x)
786 (vector (car x) (list (car x)) t)))
787 (reverse choices))))))
788 (setq val (and val
789 (listp (event-object val))
790 (stringp (car-safe (event-object val)))
791 (car (event-object val))))
792 (cdr (assoc val choices))))
793 (t
794 (cdr (assoc (completing-read (concat tag ": ")
795 choices nil t)
796 choices)))))))
797 (when current 1071 (when current
798 (widget-value-set widget (widget-value current)) 1072 (widget-value-set widget
799 (widget-setup))) 1073 (widget-apply current :value-to-external
1074 (widget-get current :value)))
1075 (widget-apply widget :notify widget event)
1076 (widget-setup)))
800 ;; Notify parent. 1077 ;; Notify parent.
801 (widget-apply widget :notify widget event) 1078 (widget-apply widget :notify widget event)
802 (widget-clear-undo)) 1079 (widget-clear-undo))
803 1080
804 (defun widget-choice-validate (widget) 1081 (defun widget-choice-validate (widget)
830 found (widget-match-inline current values))) 1107 found (widget-match-inline current values)))
831 found)) 1108 found))
832 1109
833 ;;; The `toggle' Widget. 1110 ;;; The `toggle' Widget.
834 1111
835 (define-widget 'toggle 'choice 1112 (define-widget 'toggle 'menu-choice
836 "Toggle between two states." 1113 "Toggle between two states."
837 :convert-widget 'widget-toggle-convert-widget 1114 :convert-widget 'widget-toggle-convert-widget
838 :format "%[%v%]" 1115 :format "%v"
839 :on "on" 1116 :on "on"
840 :off "off") 1117 :off "off")
841 1118
842 (defun widget-toggle-convert-widget (widget) 1119 (defun widget-toggle-convert-widget (widget)
843 ;; Create the types representing the `on' and `off' states. 1120 ;; Create the types representing the `on' and `off' states.
844 (let ((args (widget-get widget :args)) 1121 (let ((on-type (widget-get widget :on-type))
845 (on-type (widget-get widget :on-type))
846 (off-type (widget-get widget :off-type))) 1122 (off-type (widget-get widget :off-type)))
847 (unless on-type 1123 (unless on-type
848 (setq on-type (list 'item :value t :tag (widget-get widget :on)))) 1124 (setq on-type
1125 (list 'choice-item
1126 :value t
1127 :match (lambda (widget value) value)
1128 :tag (widget-get widget :on))))
849 (unless off-type 1129 (unless off-type
850 (setq off-type (list 'item :value nil :tag (widget-get widget :off)))) 1130 (setq off-type
1131 (list 'choice-item :value nil :tag (widget-get widget :off))))
851 (widget-put widget :args (list on-type off-type))) 1132 (widget-put widget :args (list on-type off-type)))
852 widget) 1133 widget)
853 1134
854 ;;; The `checkbox' Widget. 1135 ;;; The `checkbox' Widget.
855 1136
856 (define-widget 'checkbox 'toggle 1137 (define-widget 'checkbox 'toggle
857 "A checkbox toggle." 1138 "A checkbox toggle."
858 :convert-widget 'widget-item-convert-widget 1139 :convert-widget 'widget-item-convert-widget
859 :on-type '(item :format "[X]" t) 1140 :on-type '(choice-item :format "%[[X]%]" t)
860 :off-type '(item :format "[ ]" nil)) 1141 :off-type '(choice-item :format "%[[ ]%]" nil))
861 1142
862 ;;; The `checklist' Widget. 1143 ;;; The `checklist' Widget.
863 1144
864 (define-widget 'checklist 'default 1145 (define-widget 'checklist 'default
865 "A multiple choice widget." 1146 "A multiple choice widget."
866 :convert-widget 'widget-choice-convert-widget 1147 :convert-widget 'widget-types-convert-widget
867 :format "%v" 1148 :format "%v"
1149 :offset 4
868 :entry-format "%b %v" 1150 :entry-format "%b %v"
869 :menu-tag "checklist" 1151 :menu-tag "checklist"
1152 :greedy nil
870 :value-create 'widget-checklist-value-create 1153 :value-create 'widget-checklist-value-create
871 :value-delete 'widget-radio-value-delete 1154 :value-delete 'widget-children-value-delete
872 :value-get 'widget-checklist-value-get 1155 :value-get 'widget-checklist-value-get
873 :validate 'widget-checklist-validate 1156 :validate 'widget-checklist-validate
874 :match 'widget-checklist-match 1157 :match 'widget-checklist-match
875 :match-inline 'widget-checklist-match-inline) 1158 :match-inline 'widget-checklist-match-inline)
876 1159
884 (widget-put widget :children (nreverse (widget-get widget :children))))) 1167 (widget-put widget :children (nreverse (widget-get widget :children)))))
885 1168
886 (defun widget-checklist-add-item (widget type chosen) 1169 (defun widget-checklist-add-item (widget type chosen)
887 ;; Create checklist item in WIDGET of type TYPE. 1170 ;; Create checklist item in WIDGET of type TYPE.
888 ;; If the item is checked, CHOSEN is a cons whose cdr is the value. 1171 ;; If the item is checked, CHOSEN is a cons whose cdr is the value.
1172 (and (eq (preceding-char) ?\n)
1173 (widget-get widget :indent)
1174 (insert-char ? (widget-get widget :indent)))
889 (widget-specify-insert 1175 (widget-specify-insert
890 (let* ((children (widget-get widget :children)) 1176 (let* ((children (widget-get widget :children))
891 (buttons (widget-get widget :buttons)) 1177 (buttons (widget-get widget :buttons))
892 (from (point)) 1178 (from (point))
893 child button) 1179 child button)
898 (let ((escape (aref (match-string 1) 0))) 1184 (let ((escape (aref (match-string 1) 0)))
899 (replace-match "" t t) 1185 (replace-match "" t t)
900 (cond ((eq escape ?%) 1186 (cond ((eq escape ?%)
901 (insert "%")) 1187 (insert "%"))
902 ((eq escape ?b) 1188 ((eq escape ?b)
903 (setq button (widget-create 'checkbox 1189 (setq button (widget-create-child-and-convert
904 :parent widget 1190 widget 'checkbox :value (not (null chosen)))))
905 :value (not (null chosen)))))
906 ((eq escape ?v) 1191 ((eq escape ?v)
907 (setq child 1192 (setq child
908 (cond ((not chosen) 1193 (cond ((not chosen)
909 (widget-create type :parent widget)) 1194 (widget-create-child widget type))
910 ((widget-get type :inline) 1195 ((widget-get type :inline)
911 (widget-create type 1196 (widget-create-child-value
912 :parent widget 1197 widget type (cdr chosen)))
913 :value (cdr chosen)))
914 (t 1198 (t
915 (widget-create type 1199 (widget-create-child-value
916 :parent widget 1200 widget type (car (cdr chosen)))))))
917 :value (car (cdr chosen)))))))
918 (t 1201 (t
919 (error "Unknown escape `%c'" escape))))) 1202 (error "Unknown escape `%c'" escape)))))
920 ;; Update properties. 1203 ;; Update properties.
921 (and button child (widget-put child :button button)) 1204 (and button child (widget-put child :button button))
922 (and button (widget-put widget :buttons (cons button buttons))) 1205 (and button (widget-put widget :buttons (cons button buttons)))
945 (t 1228 (t
946 (setq rest (append rest values) 1229 (setq rest (append rest values)
947 values nil))))) 1230 values nil)))))
948 (cons found rest))) 1231 (cons found rest)))
949 1232
950 (defun widget-checklist-match-find (widget values) 1233 (defun widget-checklist-match-find (widget vals)
951 ;; Find the values which match a type in the checklist. 1234 ;; Find the vals which match a type in the checklist.
952 ;; Return an alist of (TYPE MATCH). 1235 ;; Return an alist of (TYPE MATCH).
953 (let ((greedy (widget-get widget :greedy)) 1236 (let ((greedy (widget-get widget :greedy))
954 (args (copy-list (widget-get widget :args))) 1237 (args (copy-list (widget-get widget :args)))
955 found) 1238 found)
956 (while values 1239 (while vals
957 (let ((answer (widget-checklist-match-up args values))) 1240 (let ((answer (widget-checklist-match-up args vals)))
958 (cond (answer 1241 (cond (answer
959 (let ((vals (widget-match-inline answer values))) 1242 (let ((match (widget-match-inline answer vals)))
960 (setq found (cons (cons answer (car vals)) found) 1243 (setq found (cons (cons answer (car match)) found)
961 values (cdr vals) 1244 vals (cdr match)
962 args (delq answer args)))) 1245 args (delq answer args))))
963 (greedy 1246 (greedy
964 (setq values (cdr values))) 1247 (setq vals (cdr vals)))
965 (t 1248 (t
966 (setq values nil))))) 1249 (setq vals nil)))))
967 found)) 1250 found))
968 1251
969 (defun widget-checklist-match-up (args values) 1252 (defun widget-checklist-match-up (args vals)
970 ;; Rerturn the first type from ARGS that matches VALUES. 1253 ;; Rerturn the first type from ARGS that matches VALS.
971 (let (current found) 1254 (let (current found)
972 (while (and args (null found)) 1255 (while (and args (null found))
973 (setq current (car args) 1256 (setq current (car args)
974 args (cdr args) 1257 args (cdr args)
975 found (widget-match-inline current values))) 1258 found (widget-match-inline current vals)))
976 (and found current))) 1259 (if found
1260 current
1261 nil)))
977 1262
978 (defun widget-checklist-value-get (widget) 1263 (defun widget-checklist-value-get (widget)
979 ;; The values of all selected items. 1264 ;; The values of all selected items.
980 (let ((children (widget-get widget :children)) 1265 (let ((children (widget-get widget :children))
981 child result) 1266 child result)
1007 ;;; The `choice-item' Widget. 1292 ;;; The `choice-item' Widget.
1008 1293
1009 (define-widget 'choice-item 'item 1294 (define-widget 'choice-item 'item
1010 "Button items that delegate action events to their parents." 1295 "Button items that delegate action events to their parents."
1011 :action 'widget-choice-item-action 1296 :action 'widget-choice-item-action
1012 :format "%[%t%]\n") 1297 :format "%[%t%] \n")
1013 1298
1014 (defun widget-choice-item-action (widget &optional event) 1299 (defun widget-choice-item-action (widget &optional event)
1015 ;; Tell parent what happened. 1300 ;; Tell parent what happened.
1016 (widget-apply (widget-get widget :parent) :action event)) 1301 (widget-apply (widget-get widget :parent) :action event))
1017 1302
1018 ;;; The `radio-button' Widget. 1303 ;;; The `radio-button' Widget.
1019 1304
1020 (define-widget 'radio-button 'toggle 1305 (define-widget 'radio-button 'toggle
1021 "A radio button for use in the `radio' widget." 1306 "A radio button for use in the `radio' widget."
1022 :format "%v"
1023 :notify 'widget-radio-button-notify 1307 :notify 'widget-radio-button-notify
1024 :on-type '(choice-item :format "%[(*)%]" t) 1308 :on-type '(choice-item :format "%[(*)%]" t)
1025 :off-type '(choice-item :format "%[( )%]" nil)) 1309 :off-type '(choice-item :format "%[( )%]" nil))
1026 1310
1027 (defun widget-radio-button-notify (widget child &optional event) 1311 (defun widget-radio-button-notify (widget child &optional event)
1028 ;; Notify the parent. 1312 ;; Notify the parent.
1029 (widget-apply (widget-get widget :parent) :action widget event)) 1313 (widget-apply (widget-get widget :parent) :action widget event))
1030 1314
1031 ;;; The `radio' Widget. 1315 ;;; The `radio-button-choice' Widget.
1032 1316
1033 (define-widget 'radio 'default 1317 (define-widget 'radio-button-choice 'default
1034 "Select one of multiple options." 1318 "Select one of multiple options."
1035 :convert-widget 'widget-choice-convert-widget 1319 :convert-widget 'widget-types-convert-widget
1320 :offset 4
1036 :format "%v" 1321 :format "%v"
1037 :entry-format "%b %v" 1322 :entry-format "%b %v"
1038 :menu-tag "radio" 1323 :menu-tag "radio"
1039 :value-create 'widget-radio-value-create 1324 :value-create 'widget-radio-value-create
1040 :value-delete 'widget-radio-value-delete 1325 :value-delete 'widget-children-value-delete
1041 :value-get 'widget-radio-value-get 1326 :value-get 'widget-radio-value-get
1042 :value-inline 'widget-radio-value-inline 1327 :value-inline 'widget-radio-value-inline
1043 :value-set 'widget-radio-value-set 1328 :value-set 'widget-radio-value-set
1044 :error "You must push one of the buttons" 1329 :error "You must push one of the buttons"
1045 :validate 'widget-radio-validate 1330 :validate 'widget-radio-validate
1048 :action 'widget-radio-action) 1333 :action 'widget-radio-action)
1049 1334
1050 (defun widget-radio-value-create (widget) 1335 (defun widget-radio-value-create (widget)
1051 ;; Insert all values 1336 ;; Insert all values
1052 (let ((args (widget-get widget :args)) 1337 (let ((args (widget-get widget :args))
1053 (indent (widget-get widget :indent))
1054 arg) 1338 arg)
1055 (while args 1339 (while args
1056 (setq arg (car args) 1340 (setq arg (car args)
1057 args (cdr args)) 1341 args (cdr args))
1058 (widget-radio-add-item widget arg) 1342 (widget-radio-add-item widget arg))))
1059 (and indent args (insert-char ?\ indent)))))
1060 1343
1061 (defun widget-radio-add-item (widget type) 1344 (defun widget-radio-add-item (widget type)
1062 "Add to radio widget WIDGET a new radio button item of type TYPE." 1345 "Add to radio widget WIDGET a new radio button item of type TYPE."
1063 (setq type (widget-convert type)) 1346 ;; (setq type (widget-convert type))
1347 (and (eq (preceding-char) ?\n)
1348 (widget-get widget :indent)
1349 (insert-char ? (widget-get widget :indent)))
1064 (widget-specify-insert 1350 (widget-specify-insert
1065 (let* ((value (widget-get widget :value)) 1351 (let* ((value (widget-get widget :value))
1066 (children (widget-get widget :children)) 1352 (children (widget-get widget :children))
1067 (buttons (widget-get widget :buttons)) 1353 (buttons (widget-get widget :buttons))
1068 (from (point)) 1354 (from (point))
1076 (let ((escape (aref (match-string 1) 0))) 1362 (let ((escape (aref (match-string 1) 0)))
1077 (replace-match "" t t) 1363 (replace-match "" t t)
1078 (cond ((eq escape ?%) 1364 (cond ((eq escape ?%)
1079 (insert "%")) 1365 (insert "%"))
1080 ((eq escape ?b) 1366 ((eq escape ?b)
1081 (setq button (widget-create 'radio-button 1367 (setq button (widget-create-child-and-convert
1082 :parent widget 1368 widget 'radio-button
1083 :value (not (null chosen))))) 1369 :value (not (null chosen)))))
1084 ((eq escape ?v) 1370 ((eq escape ?v)
1085 (setq child (if chosen 1371 (setq child (if chosen
1086 (widget-create type 1372 (widget-create-child-value
1087 :parent widget 1373 widget type value)
1088 :value value) 1374 (widget-create-child widget type))))
1089 (widget-create type :parent widget))))
1090 (t 1375 (t
1091 (error "Unknown escape `%c'" escape))))) 1376 (error "Unknown escape `%c'" escape)))))
1092 ;; Update properties. 1377 ;; Update properties.
1093 (when chosen 1378 (when chosen
1094 (widget-put widget :choice type)) 1379 (widget-put widget :choice type))
1096 (widget-put child :button button) 1381 (widget-put child :button button)
1097 (widget-put widget :buttons (nconc buttons (list button)))) 1382 (widget-put widget :buttons (nconc buttons (list button))))
1098 (when child 1383 (when child
1099 (widget-put widget :children (nconc children (list child)))) 1384 (widget-put widget :children (nconc children (list child))))
1100 child))) 1385 child)))
1101
1102 (defun widget-radio-value-delete (widget)
1103 ;; Delete the child widgets.
1104 (mapcar 'widget-delete (widget-get widget :children))
1105 (widget-put widget :children nil)
1106 (mapcar 'widget-delete (widget-get widget :buttons))
1107 (widget-put widget :buttons nil))
1108 1386
1109 (defun widget-radio-value-get (widget) 1387 (defun widget-radio-value-get (widget)
1110 ;; Get value of the child widget. 1388 ;; Get value of the child widget.
1111 (let ((chosen (widget-radio-chosen widget))) 1389 (let ((chosen (widget-radio-chosen widget)))
1112 (and chosen (widget-value chosen)))) 1390 (and chosen (widget-value chosen))))
1186 ;; Pass notification to parent. 1464 ;; Pass notification to parent.
1187 (widget-apply widget :notify child event)) 1465 (widget-apply widget :notify child event))
1188 1466
1189 ;;; The `insert-button' Widget. 1467 ;;; The `insert-button' Widget.
1190 1468
1191 (define-widget 'insert-button 'push 1469 (define-widget 'insert-button 'push-button
1192 "An insert button for the `repeat' widget." 1470 "An insert button for the `editable-list' widget."
1193 :tag "INS" 1471 :tag "INS"
1194 :action 'widget-insert-button-action) 1472 :action 'widget-insert-button-action)
1195 1473
1196 (defun widget-insert-button-action (widget &optional event) 1474 (defun widget-insert-button-action (widget &optional event)
1197 ;; Ask the parent to insert a new item. 1475 ;; Ask the parent to insert a new item.
1198 (widget-apply (widget-get widget :parent) 1476 (widget-apply (widget-get widget :parent)
1199 :insert-before (widget-get widget :widget))) 1477 :insert-before (widget-get widget :widget)))
1200 1478
1201 ;;; The `delete-button' Widget. 1479 ;;; The `delete-button' Widget.
1202 1480
1203 (define-widget 'delete-button 'push 1481 (define-widget 'delete-button 'push-button
1204 "A delete button for the `repeat' widget." 1482 "A delete button for the `editable-list' widget."
1205 :tag "DEL" 1483 :tag "DEL"
1206 :action 'widget-delete-button-action) 1484 :action 'widget-delete-button-action)
1207 1485
1208 (defun widget-delete-button-action (widget &optional event) 1486 (defun widget-delete-button-action (widget &optional event)
1209 ;; Ask the parent to insert a new item. 1487 ;; Ask the parent to insert a new item.
1210 (widget-apply (widget-get widget :parent) 1488 (widget-apply (widget-get widget :parent)
1211 :delete-at (widget-get widget :widget))) 1489 :delete-at (widget-get widget :widget)))
1212 1490
1213 ;;; The `repeat' Widget. 1491 ;;; The `editable-list' Widget.
1214 1492
1215 (define-widget 'repeat 'default 1493 (define-widget 'editable-list 'default
1216 "A variable list of widgets of the same type." 1494 "A variable list of widgets of the same type."
1217 :convert-widget 'widget-choice-convert-widget 1495 :convert-widget 'widget-types-convert-widget
1496 :offset 12
1218 :format "%v%i\n" 1497 :format "%v%i\n"
1219 :format-handler 'widget-repeat-format-handler 1498 :format-handler 'widget-editable-list-format-handler
1220 :entry-format "%i %d %v" 1499 :entry-format "%i %d %v"
1221 :menu-tag "repeat" 1500 :menu-tag "editable-list"
1222 :value-create 'widget-repeat-value-create 1501 :value-create 'widget-editable-list-value-create
1223 :value-delete 'widget-radio-value-delete 1502 :value-delete 'widget-children-value-delete
1224 :value-get 'widget-repeat-value-get 1503 :value-get 'widget-editable-list-value-get
1225 :validate 'widget-repeat-validate 1504 :validate 'widget-editable-list-validate
1226 :match 'widget-repeat-match 1505 :match 'widget-editable-list-match
1227 :match-inline 'widget-repeat-match-inline 1506 :match-inline 'widget-editable-list-match-inline
1228 :insert-before 'widget-repeat-insert-before 1507 :insert-before 'widget-editable-list-insert-before
1229 :delete-at 'widget-repeat-delete-at) 1508 :delete-at 'widget-editable-list-delete-at)
1230 1509
1231 (defun widget-repeat-format-handler (widget escape) 1510 (defun widget-editable-list-format-handler (widget escape)
1232 ;; We recognize the insert button. 1511 ;; We recognize the insert button.
1233 (cond ((eq escape ?i) 1512 (cond ((eq escape ?i)
1234 (insert " ") 1513 (and (widget-get widget :indent)
1235 (backward-char 1) 1514 (insert-char ? (widget-get widget :indent)))
1236 (let* ((from (point)) 1515 (widget-create-child-and-convert widget 'insert-button))
1237 (button (widget-create (list 'insert-button
1238 :parent widget))))
1239 (widget-specify-button button from (point)))
1240 (forward-char 1))
1241 (t 1516 (t
1242 (widget-default-format-handler widget escape)))) 1517 (widget-default-format-handler widget escape))))
1243 1518
1244 (defun widget-repeat-value-create (widget) 1519 (defun widget-editable-list-value-create (widget)
1245 ;; Insert all values 1520 ;; Insert all values
1246 (let* ((value (widget-get widget :value)) 1521 (let* ((value (widget-get widget :value))
1247 (type (nth 0 (widget-get widget :args))) 1522 (type (nth 0 (widget-get widget :args)))
1248 (inlinep (widget-get type :inline)) 1523 (inlinep (widget-get type :inline))
1249 children) 1524 children)
1250 (widget-put widget :value-pos (copy-marker (point))) 1525 (widget-put widget :value-pos (copy-marker (point)))
1251 (set-marker-insertion-type (widget-get widget :value-pos) t) 1526 (set-marker-insertion-type (widget-get widget :value-pos) t)
1252 (while value 1527 (while value
1253 (let ((answer (widget-match-inline type value))) 1528 (let ((answer (widget-match-inline type value)))
1254 (if answer 1529 (if answer
1255 (setq children (cons (widget-repeat-entry-create 1530 (setq children (cons (widget-editable-list-entry-create
1256 widget (if inlinep 1531 widget
1257 (car answer) 1532 (if inlinep
1258 (car (car answer)))) 1533 (car answer)
1534 (car (car answer)))
1535 t)
1259 children) 1536 children)
1260 value (cdr answer)) 1537 value (cdr answer))
1261 (setq value nil)))) 1538 (setq value nil))))
1262 (widget-put widget :children (nreverse children)))) 1539 (widget-put widget :children (nreverse children))))
1263 1540
1264 (defun widget-repeat-value-get (widget) 1541 (defun widget-editable-list-value-get (widget)
1265 ;; Get value of the child widget. 1542 ;; Get value of the child widget.
1266 (apply 'append (mapcar (lambda (child) (widget-apply child :value-inline)) 1543 (apply 'append (mapcar (lambda (child) (widget-apply child :value-inline))
1267 (widget-get widget :children)))) 1544 (widget-get widget :children))))
1268 1545
1269 (defun widget-repeat-validate (widget) 1546 (defun widget-editable-list-validate (widget)
1270 ;; All the chilren must be valid. 1547 ;; All the chilren must be valid.
1271 (let ((children (widget-get widget :children)) 1548 (let ((children (widget-get widget :children))
1272 child found) 1549 child found)
1273 (while (and children (not found)) 1550 (while (and children (not found))
1274 (setq child (car children) 1551 (setq child (car children)
1275 children (cdr children) 1552 children (cdr children)
1276 found (widget-apply child :validate))) 1553 found (widget-apply child :validate)))
1277 found)) 1554 found))
1278 1555
1279 (defun widget-repeat-match (widget value) 1556 (defun widget-editable-list-match (widget value)
1280 ;; Value must be a list and all the members must match the repeat type. 1557 ;; Value must be a list and all the members must match the type.
1281 (and (listp value) 1558 (and (listp value)
1282 (null (cdr (widget-repeat-match-inline widget value))))) 1559 (null (cdr (widget-editable-list-match-inline widget value)))))
1283 1560
1284 (defun widget-repeat-match-inline (widget value) 1561 (defun widget-editable-list-match-inline (widget value)
1285 (let ((type (nth 0 (widget-get widget :args))) 1562 (let ((type (nth 0 (widget-get widget :args)))
1286 (ok t) 1563 (ok t)
1287 found) 1564 found)
1288 (while (and value ok) 1565 (while (and value ok)
1289 (let ((answer (widget-match-inline type value))) 1566 (let ((answer (widget-match-inline type value)))
1291 (setq found (append found (car answer)) 1568 (setq found (append found (car answer))
1292 value (cdr answer)) 1569 value (cdr answer))
1293 (setq ok nil)))) 1570 (setq ok nil))))
1294 (cons found value))) 1571 (cons found value)))
1295 1572
1296 (defun widget-repeat-insert-before (widget before) 1573 (defun widget-editable-list-insert-before (widget before)
1297 ;; Insert a new child in the list of children. 1574 ;; Insert a new child in the list of children.
1298 (save-excursion 1575 (save-excursion
1299 (let ((children (widget-get widget :children)) 1576 (let ((children (widget-get widget :children))
1300 (inhibit-read-only t) 1577 (inhibit-read-only t)
1301 after-change-functions) 1578 after-change-functions)
1302 (cond (before 1579 (cond (before
1303 (goto-char (widget-get before :from))) 1580 (goto-char (widget-get before :entry-from)))
1304 (t 1581 (t
1305 (goto-char (widget-get widget :value-pos)))) 1582 (goto-char (widget-get widget :value-pos))))
1306 (let ((child (widget-repeat-entry-create 1583 (let ((child (widget-editable-list-entry-create
1307 widget (widget-get (nth 0 (widget-get widget :args)) 1584 widget nil nil)))
1308 :value)))) 1585 (when (< (widget-get child :entry-from) (widget-get widget :from))
1309 (widget-specify-text (widget-get child :from) 1586 (set-marker (widget-get widget :from)
1310 (widget-get child :to)) 1587 (widget-get child :entry-from)))
1588 (widget-specify-text (widget-get child :entry-from)
1589 (widget-get child :entry-to))
1311 (if (eq (car children) before) 1590 (if (eq (car children) before)
1312 (widget-put widget :children (cons child children)) 1591 (widget-put widget :children (cons child children))
1313 (while (not (eq (car (cdr children)) before)) 1592 (while (not (eq (car (cdr children)) before))
1314 (setq children (cdr children))) 1593 (setq children (cdr children)))
1315 (setcdr children (cons child (cdr children))))))) 1594 (setcdr children (cons child (cdr children)))))))
1316 (widget-setup) 1595 (widget-setup)
1317 (widget-apply widget :notify widget)) 1596 (widget-apply widget :notify widget))
1318 1597
1319 (defun widget-repeat-delete-at (widget child) 1598 (defun widget-editable-list-delete-at (widget child)
1320 ;; Delete child from list of children. 1599 ;; Delete child from list of children.
1321 (save-excursion 1600 (save-excursion
1322 (let ((buttons (copy-list (widget-get widget :buttons))) 1601 (let ((buttons (copy-list (widget-get widget :buttons)))
1323 button 1602 button
1324 (inhibit-read-only t) 1603 (inhibit-read-only t)
1328 buttons (cdr buttons)) 1607 buttons (cdr buttons))
1329 (when (eq (widget-get button :widget) child) 1608 (when (eq (widget-get button :widget) child)
1330 (widget-put widget 1609 (widget-put widget
1331 :buttons (delq button (widget-get widget :buttons))) 1610 :buttons (delq button (widget-get widget :buttons)))
1332 (widget-delete button)))) 1611 (widget-delete button))))
1333 (widget-delete child) 1612 (let ((entry-from (widget-get child :entry-from))
1613 (entry-to (widget-get child :entry-to))
1614 (inhibit-read-only t)
1615 after-change-functions)
1616 (widget-delete child)
1617 (delete-region entry-from entry-to)
1618 (set-marker entry-from nil)
1619 (set-marker entry-to nil))
1334 (widget-put widget :children (delq child (widget-get widget :children)))) 1620 (widget-put widget :children (delq child (widget-get widget :children))))
1335 (widget-setup) 1621 (widget-setup)
1336 (widget-apply widget :notify widget)) 1622 (widget-apply widget :notify widget))
1337 1623
1338 (defun widget-repeat-entry-create (widget value) 1624 (defun widget-editable-list-entry-create (widget value conv)
1339 ;; Create a new entry to the list. 1625 ;; Create a new entry to the list.
1340 (let ((type (nth 0 (widget-get widget :args))) 1626 (let ((type (nth 0 (widget-get widget :args)))
1341 (indent (widget-get widget :indent))
1342 child delete insert) 1627 child delete insert)
1343 (widget-specify-insert 1628 (widget-specify-insert
1344 (save-excursion 1629 (save-excursion
1345 (insert (widget-get widget :entry-format)) 1630 (and (widget-get widget :indent)
1346 (if indent 1631 (insert-char ? (widget-get widget :indent)))
1347 (insert-char ?\ indent))) 1632 (insert (widget-get widget :entry-format)))
1348 ;; Parse % escapes in format. 1633 ;; Parse % escapes in format.
1349 (while (re-search-forward "%\\(.\\)" nil t) 1634 (while (re-search-forward "%\\(.\\)" nil t)
1350 (let ((escape (aref (match-string 1) 0))) 1635 (let ((escape (aref (match-string 1) 0)))
1351 (replace-match "" t t) 1636 (replace-match "" t t)
1352 (cond ((eq escape ?%) 1637 (cond ((eq escape ?%)
1353 (insert "%")) 1638 (insert "%"))
1354 ((eq escape ?i) 1639 ((eq escape ?i)
1355 (setq insert (widget-create 'insert-button 1640 (setq insert (widget-create-child-and-convert
1356 :parent widget))) 1641 widget 'insert-button)))
1357 ((eq escape ?d) 1642 ((eq escape ?d)
1358 (setq delete (widget-create 'delete-button 1643 (setq delete (widget-create-child-and-convert
1359 :parent widget))) 1644 widget 'delete-button)))
1360 ((eq escape ?v) 1645 ((eq escape ?v)
1361 (setq child (widget-create type 1646 (if conv
1362 :parent widget 1647 (setq child (widget-create-child-value
1363 :value value))) 1648 widget type value))
1649 (setq child (widget-create-child widget type))))
1364 (t 1650 (t
1365 (error "Unknown escape `%c'" escape))))) 1651 (error "Unknown escape `%c'" escape)))))
1366 (widget-put widget 1652 (widget-put widget
1367 :buttons (cons delete 1653 :buttons (cons delete
1368 (cons insert 1654 (cons insert
1369 (widget-get widget :buttons)))) 1655 (widget-get widget :buttons))))
1370 (move-marker (widget-get child :from) (point-min)) 1656 (let ((entry-from (copy-marker (point-min)))
1371 (move-marker (widget-get child :to) (point-max))) 1657 (entry-to (copy-marker (point-max))))
1658 (widget-specify-text entry-from entry-to)
1659 (set-marker-insertion-type entry-from t)
1660 (set-marker-insertion-type entry-to nil)
1661 (widget-put child :entry-from entry-from)
1662 (widget-put child :entry-to entry-to)))
1372 (widget-put insert :widget child) 1663 (widget-put insert :widget child)
1373 (widget-put delete :widget child) 1664 (widget-put delete :widget child)
1374 child)) 1665 child))
1375 1666
1376 ;;; The `group' Widget. 1667 ;;; The `group' Widget.
1377 1668
1378 (define-widget 'group 'default 1669 (define-widget 'group 'default
1379 "A widget which group other widgets inside." 1670 "A widget which group other widgets inside."
1380 :convert-widget 'widget-choice-convert-widget 1671 :convert-widget 'widget-types-convert-widget
1381 :format "%v" 1672 :format "%v"
1382 :value-create 'widget-group-value-create 1673 :value-create 'widget-group-value-create
1383 :value-delete 'widget-radio-value-delete 1674 :value-delete 'widget-children-value-delete
1384 :value-get 'widget-repeat-value-get 1675 :value-get 'widget-editable-list-value-get
1385 :validate 'widget-repeat-validate 1676 :validate 'widget-editable-list-validate
1386 :match 'widget-group-match 1677 :match 'widget-group-match
1387 :match-inline 'widget-group-match-inline) 1678 :match-inline 'widget-group-match-inline)
1388 1679
1389 (defun widget-group-value-create (widget) 1680 (defun widget-group-value-create (widget)
1390 ;; Create each component. 1681 ;; Create each component.
1391 (let ((args (widget-get widget :args)) 1682 (let ((args (widget-get widget :args))
1392 (value (widget-get widget :value)) 1683 (value (widget-get widget :value))
1393 (indent (widget-get widget :indent))
1394 arg answer children) 1684 arg answer children)
1395 (while args 1685 (while args
1396 (setq arg (car args) 1686 (setq arg (car args)
1397 args (cdr args) 1687 args (cdr args)
1398 answer (widget-match-inline arg value) 1688 answer (widget-match-inline arg value)
1399 value (cdr answer) 1689 value (cdr answer))
1400 children (cons (cond ((null answer) 1690 (and (eq (preceding-char) ?\n)
1401 (widget-create arg :parent widget)) 1691 (widget-get widget :indent)
1402 ((widget-get arg :inline) 1692 (insert-char ? (widget-get widget :indent)))
1403 (widget-create arg 1693 (push (cond ((null answer)
1404 :parent widget 1694 (widget-create-child widget arg))
1405 :value (car answer))) 1695 ((widget-get arg :inline)
1406 (t 1696 (widget-create-child-value widget arg (car answer)))
1407 (widget-create arg 1697 (t
1408 :parent widget 1698 (widget-create-child-value widget arg (car (car answer)))))
1409 :value (car (car answer))))) 1699 children))
1410 children))
1411 (and args indent (insert-char ?\ indent)))
1412 (widget-put widget :children (nreverse children)))) 1700 (widget-put widget :children (nreverse children))))
1413 1701
1414 (defun widget-group-match (widget values) 1702 (defun widget-group-match (widget values)
1415 ;; Match if the components match. 1703 ;; Match if the components match.
1416 (and (listp values) 1704 (and (listp values)
1417 (null (cdr (widget-group-match-inline widget values))))) 1705 (let ((match (widget-group-match-inline widget values)))
1418 1706 (and match (null (cdr match))))))
1419 (defun widget-group-match-inline (widget values) 1707
1708 (defun widget-group-match-inline (widget vals)
1420 ;; Match if the components match. 1709 ;; Match if the components match.
1421 (let ((args (widget-get widget :args)) 1710 (let ((args (widget-get widget :args))
1422 (match t) 1711 argument answer found)
1423 arg answer found)
1424 (while args 1712 (while args
1425 (setq arg (car args) 1713 (setq argument (car args)
1426 args (cdr args) 1714 args (cdr args)
1427 answer (widget-match-inline arg values)) 1715 answer (widget-match-inline argument vals))
1428 (if answer 1716 (if answer
1429 (setq values (cdr answer) 1717 (setq vals (cdr answer)
1430 found (append found (car answer))) 1718 found (append found (car answer)))
1431 (setq values nil))) 1719 (setq vals nil
1720 args nil)))
1432 (if answer 1721 (if answer
1433 (cons found values) 1722 (cons found vals)
1434 nil))) 1723 nil)))
1435 1724
1725 ;;; The `widget-help' Widget.
1726
1727 (define-widget 'widget-help 'push-button
1728 "The widget documentation button."
1729 :format "%[[%t]%] %d"
1730 :help-echo "Push me to toggle the documentation."
1731 :action 'widget-help-action)
1732
1733 (defun widget-help-action (widget &optional event)
1734 "Toggle documentation for WIDGET."
1735 (let ((old (widget-get widget :doc))
1736 (new (widget-get widget :widget-doc)))
1737 (widget-put widget :doc new)
1738 (widget-put widget :widget-doc old))
1739 (widget-value-set widget (widget-value widget)))
1740
1436 ;;; The Sexp Widgets. 1741 ;;; The Sexp Widgets.
1437 1742
1438 (define-widget 'const 'item 1743 (define-widget 'const 'item
1439 nil 1744 "An immutable sexp."
1440 :format "%t\n") 1745 :format "%t\n%d")
1441 1746
1442 (define-widget 'string 'field 1747 (define-widget 'function-item 'item
1443 nil) 1748 "An immutable function name."
1749 :format "%v\n%h"
1750 :documentation-property (lambda (symbol)
1751 (condition-case nil
1752 (documentation symbol t)
1753 (error nil))))
1754
1755 (define-widget 'variable-item 'item
1756 "An immutable variable name."
1757 :format "%v\n%h"
1758 :documentation-property 'variable-documentation)
1759
1760 (define-widget 'string 'editable-field
1761 "A string"
1762 :tag "String"
1763 :format "%[%t%]: %v")
1764
1765 (define-widget 'regexp 'string
1766 "A regular expression."
1767 ;; Should do validation.
1768 :tag "Regexp")
1444 1769
1445 (define-widget 'file 'string 1770 (define-widget 'file 'string
1446 nil 1771 "A file widget.
1447 :format "%[%t%]:%v" 1772 It will read a file name from the minibuffer when activated."
1773 :format "%[%t%]: %v"
1448 :tag "File" 1774 :tag "File"
1449 :action 'widget-file-action) 1775 :action 'widget-file-action)
1450 1776
1451 (defun widget-file-action (widget &optional event) 1777 (defun widget-file-action (widget &optional event)
1452 nil
1453 ;; Read a file name from the minibuffer. 1778 ;; Read a file name from the minibuffer.
1454 (widget-value-set widget 1779 (let* ((value (widget-value widget))
1455 (read-file-name (widget-apply widget :menu-tag-get) 1780 (dir (file-name-directory value))
1456 (widget-get widget :directory) 1781 (file (file-name-nondirectory value))
1457 (widget-value widget) 1782 (menu-tag (widget-apply widget :menu-tag-get))
1458 (widget-get widget :must-match) 1783 (must-match (widget-get widget :must-match))
1459 (widget-get widget :initial)))) 1784 (answer (read-file-name (concat menu-tag ": (defalt `" value "') ")
1785 dir nil must-match file)))
1786 (widget-value-set widget (abbreviate-file-name answer))
1787 (widget-apply widget :notify widget event)
1788 (widget-setup)))
1460 1789
1461 (define-widget 'directory 'file 1790 (define-widget 'directory 'file
1462 nil 1791 "A directory widget.
1792 It will read a directory name from the minibuffer when activated."
1463 :tag "Directory") 1793 :tag "Directory")
1464 1794
1465 (define-widget 'symbol 'string 1795 (define-widget 'symbol 'string
1466 nil 1796 "A lisp symbol."
1797 :value nil
1798 :tag "Symbol"
1467 :match (lambda (widget value) (symbolp value)) 1799 :match (lambda (widget value) (symbolp value))
1468 :value-to-internal (lambda (widget value) (symbol-name value)) 1800 :value-to-internal (lambda (widget value)
1469 :value-to-external (lambda (widget value) (intern value))) 1801 (if (symbolp value)
1802 (symbol-name value)
1803 value))
1804 :value-to-external (lambda (widget value)
1805 (if (stringp value)
1806 (intern value)
1807 value)))
1808
1809 (define-widget 'function 'sexp
1810 ;; Should complete on functions.
1811 "A lisp function."
1812 :tag "Function")
1813
1814 (define-widget 'variable 'symbol
1815 ;; Should complete on variables.
1816 "A lisp variable."
1817 :tag "Variable")
1470 1818
1471 (define-widget 'sexp 'string 1819 (define-widget 'sexp 'string
1472 nil 1820 "An arbitrary lisp expression."
1821 :tag "Lisp expression"
1822 :value nil
1473 :validate 'widget-sexp-validate 1823 :validate 'widget-sexp-validate
1474 :match (lambda (widget value) t) 1824 :match (lambda (widget value) t)
1475 :value-to-internal (lambda (widget value) (pp-to-string value)) 1825 :value-to-internal 'widget-sexp-value-to-internal
1476 :value-to-external (lambda (widget value) (read value))) 1826 :value-to-external (lambda (widget value) (read value)))
1827
1828 (defun widget-sexp-value-to-internal (widget value)
1829 ;; Use pp for printer representation.
1830 (let ((pp (pp-to-string value)))
1831 (while (string-match "\n\\'" pp)
1832 (setq pp (substring pp 0 -1)))
1833 (if (or (string-match "\n\\'" pp)
1834 (> (length pp) 40))
1835 (concat "\n" pp)
1836 pp)))
1477 1837
1478 (defun widget-sexp-validate (widget) 1838 (defun widget-sexp-validate (widget)
1479 ;; Valid if we can read the string and there is no junk left after it. 1839 ;; Valid if we can read the string and there is no junk left after it.
1480 (save-excursion 1840 (save-excursion
1481 (set-buffer (get-buffer-create " *Widget Scratch*")) 1841 (let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*"))))
1482 (erase-buffer) 1842 (erase-buffer)
1483 (insert (widget-apply :value-get widget)) 1843 (insert (widget-apply widget :value-get))
1484 (goto-char (point-min)) 1844 (goto-char (point-min))
1485 (condition-case data 1845 (condition-case data
1486 (let ((value (read (current-buffer)))) 1846 (let ((value (read buffer)))
1487 (if (eobp) 1847 (if (eobp)
1488 (if (widget-apply widget :match value) 1848 (if (widget-apply widget :match value)
1489 t 1849 nil
1490 (widget-put widget :error (widget-get widget :type-error)) 1850 (widget-put widget :error (widget-get widget :type-error))
1491 nil) 1851 widget)
1492 (widget-put widget 1852 (widget-put widget
1493 :error (format "Junk at end of expression: %s" 1853 :error (format "Junk at end of expression: %s"
1494 (buffer-substring (point) (point-max)))) 1854 (buffer-substring (point)
1495 nil)) 1855 (point-max))))
1496 (error (widget-put widget :error (error-message-string data)) 1856 widget))
1497 nil)))) 1857 (error (widget-put widget :error (error-message-string data))
1858 widget)))))
1498 1859
1499 (define-widget 'integer 'sexp 1860 (define-widget 'integer 'sexp
1500 nil 1861 "An integer."
1862 :tag "Integer"
1863 :value 0
1501 :type-error "This field should contain an integer" 1864 :type-error "This field should contain an integer"
1865 :value-to-internal (lambda (widget value)
1866 (if (integerp value)
1867 (prin1-to-string value)
1868 value))
1502 :match (lambda (widget value) (integerp value))) 1869 :match (lambda (widget value) (integerp value)))
1503 1870
1871 (define-widget 'character 'string
1872 "An character."
1873 :tag "Character"
1874 :value 0
1875 :size 1
1876 :format "%t: %v\n"
1877 :type-error "This field should contain a character"
1878 :value-to-internal (lambda (widget value)
1879 (if (integerp value)
1880 (char-to-string value)
1881 value))
1882 :value-to-external (lambda (widget value)
1883 (if (stringp value)
1884 (aref value 0)
1885 value))
1886 :match (lambda (widget value) (integerp value)))
1887
1504 (define-widget 'number 'sexp 1888 (define-widget 'number 'sexp
1505 nil 1889 "A floating point number."
1890 :tag "Number"
1891 :value 0.0
1506 :type-error "This field should contain a number" 1892 :type-error "This field should contain a number"
1893 :value-to-internal (lambda (widget value)
1894 (if (numberp value)
1895 (prin1-to-string value)
1896 value))
1507 :match (lambda (widget value) (numberp value))) 1897 :match (lambda (widget value) (numberp value)))
1508 1898
1509 (define-widget 'list 'group 1899 (define-widget 'list 'group
1510 nil) 1900 "A lisp list."
1901 :tag "List"
1902 :format "%t:\n%v")
1511 1903
1512 (define-widget 'vector 'group 1904 (define-widget 'vector 'group
1513 nil 1905 "A lisp vector."
1906 :tag "Vector"
1907 :format "%t:\n%v"
1514 :match 'widget-vector-match 1908 :match 'widget-vector-match
1515 :value-to-internal (lambda (widget value) (append value nil)) 1909 :value-to-internal (lambda (widget value) (append value nil))
1516 :value-to-external (lambda (widget value) (apply 'vector value))) 1910 :value-to-external (lambda (widget value) (apply 'vector value)))
1517 1911
1518 (defun widget-vector-match (widget value) 1912 (defun widget-vector-match (widget value)
1519 (and (vectorp value) 1913 (and (vectorp value)
1520 (widget-group-match widget 1914 (widget-group-match widget
1521 (widget-apply :value-to-internal widget value)))) 1915 (widget-apply :value-to-internal widget value))))
1522 1916
1523 (define-widget 'cons 'group 1917 (define-widget 'cons 'group
1524 nil 1918 "A cons-cell."
1919 :tag "Cons-cell"
1920 :format "%t:\n%v"
1525 :match 'widget-cons-match 1921 :match 'widget-cons-match
1526 :value-to-internal (lambda (widget value) 1922 :value-to-internal (lambda (widget value)
1527 (list (car value) (cdr value))) 1923 (list (car value) (cdr value)))
1528 :value-to-external (lambda (widget value) 1924 :value-to-external (lambda (widget value)
1529 (cons (nth 0 value) (nth 1 value)))) 1925 (cons (nth 0 value) (nth 1 value))))
1530 1926
1531 (defun widget-cons-match (widget value) 1927 (defun widget-cons-match (widget value)
1532 (and (consp value) 1928 (and (consp value)
1533 (widget-group-match widget 1929 (widget-group-match widget
1534 (widget-apply :value-to-internal widget value)))) 1930 (widget-apply widget :value-to-internal value))))
1931
1932 (define-widget 'choice 'menu-choice
1933 "A union of several sexp types."
1934 :tag "Choice"
1935 :format "%[%t%]: %v")
1936
1937 (define-widget 'radio 'radio-button-choice
1938 "A union of several sexp types."
1939 :tag "Choice"
1940 :format "%t:\n%v")
1941
1942 (define-widget 'repeat 'editable-list
1943 "A variable length homogeneous list."
1944 :tag "Repeat"
1945 :format "%t:\n%v%i\n")
1946
1947 (define-widget 'set 'checklist
1948 "A list of members from a fixed set."
1949 :tag "Set"
1950 :format "%t:\n%v")
1951
1952 (define-widget 'boolean 'toggle
1953 "To be nil or non-nil, that is the question."
1954 :tag "Boolean"
1955 :format "%t: %v")
1956
1957 ;;; The `color' Widget.
1958
1959 (define-widget 'color-item 'choice-item
1960 "A color name (with sample)."
1961 :format "%v (%[sample%])\n"
1962 :button-face-get 'widget-color-item-button-face-get)
1963
1964 (defun widget-color-item-button-face-get (widget)
1965 ;; We create a face from the value.
1966 (require 'facemenu)
1967 (condition-case nil
1968 (facemenu-get-face (intern (concat "fg:" (widget-value widget))))
1969 (error 'default)))
1970
1971 (define-widget 'color 'push-button
1972 "Choose a color name (with sample)."
1973 :format "%[%t%]: %v"
1974 :tag "Color"
1975 :value "default"
1976 :value-create 'widget-color-value-create
1977 :value-delete 'widget-children-value-delete
1978 :value-get 'widget-color-value-get
1979 :value-set 'widget-color-value-set
1980 :action 'widget-color-action
1981 :match 'widget-field-match
1982 :tag "Color")
1983
1984 (defvar widget-color-choice-list nil)
1985 ;; Variable holding the possible colors.
1986
1987 (defun widget-color-choice-list ()
1988 (unless widget-color-choice-list
1989 (setq widget-color-choice-list
1990 (mapcar '(lambda (color) (list color))
1991 (x-defined-colors))))
1992 widget-color-choice-list)
1993
1994 (defun widget-color-value-create (widget)
1995 (let ((child (widget-create-child-and-convert
1996 widget 'color-item (widget-get widget :value))))
1997 (widget-put widget :children (list child))))
1998
1999 (defun widget-color-value-get (widget)
2000 ;; Pass command to first child.
2001 (widget-apply (car (widget-get widget :children)) :value-get))
2002
2003 (defun widget-color-value-set (widget value)
2004 ;; Pass command to first child.
2005 (widget-apply (car (widget-get widget :children)) :value-set value))
2006
2007 (defvar widget-color-history nil
2008 "History of entered colors")
2009
2010 (defun widget-color-action (widget &optional event)
2011 ;; Prompt for a color.
2012 (let* ((tag (widget-apply widget :menu-tag-get))
2013 (prompt (concat tag ": "))
2014 (answer (cond ((string-match "XEmacs" emacs-version)
2015 (read-color prompt))
2016 ((fboundp 'x-defined-colors)
2017 (completing-read (concat tag ": ")
2018 (widget-color-choice-list)
2019 nil nil nil 'widget-color-history))
2020 (t
2021 (read-string prompt (widget-value widget))))))
2022 (unless (zerop (length answer))
2023 (widget-value-set widget answer)
2024 (widget-apply widget :notify widget event)
2025 (widget-setup))))
2026
2027 ;;; The Help Echo
2028
2029 (defun widget-echo-help-mouse ()
2030 "Display the help message for the widget under the mouse.
2031 Enable with (run-with-idle-timer 1 t 'widget-echo-help-mouse)"
2032 (let* ((pos (mouse-position))
2033 (frame (car pos))
2034 (x (car (cdr pos)))
2035 (y (cdr (cdr pos)))
2036 (win (window-at x y frame))
2037 (where (coordinates-in-window-p (cons x y) win)))
2038 (when (consp where)
2039 (save-window-excursion
2040 (progn ; save-excursion
2041 (select-window win)
2042 (let* ((result (compute-motion (window-start win)
2043 '(0 . 0)
2044 (window-end win)
2045 where
2046 (window-width win)
2047 (cons (window-hscroll) 0)
2048 win)))
2049 (when (and (eq (nth 1 result) x)
2050 (eq (nth 2 result) y))
2051 (widget-echo-help (nth 0 result))))))))
2052 (unless track-mouse
2053 (setq track-mouse t)
2054 (add-hook 'post-command-hook 'widget-stop-mouse-tracking)))
2055
2056 (defun widget-stop-mouse-tracking (&rest args)
2057 "Stop the mouse tracking done while idle."
2058 (remove-hook 'post-command-hook 'widget-stop-mouse-tracking)
2059 (setq track-mouse nil))
2060
2061 (defun widget-at (pos)
2062 "The button or field at POS."
2063 (or (get-text-property pos 'button)
2064 (get-text-property pos 'field)))
2065
2066 (defun widget-echo-help (pos)
2067 "Display the help echo for widget at POS."
2068 (let* ((widget (widget-at pos))
2069 (help-echo (and widget (widget-get widget :help-echo))))
2070 (cond ((stringp help-echo)
2071 (message "%s" help-echo))
2072 ((and (symbolp help-echo) (fboundp help-echo)
2073 (stringp (setq help-echo (funcall help-echo widget))))
2074 (message "%s" help-echo)))))
1535 2075
1536 ;;; The End: 2076 ;;; The End:
1537 2077
1538 (provide 'widget-edit) 2078 (provide 'widget-edit)
1539 2079