comparison lisp/custom/wid-edit.el @ 155:43dd3413c7c7 r20-3b4

Import from CVS: tag r20-3b4
author cvs
date Mon, 13 Aug 2007 09:39:39 +0200
parents 25f70ba0133c
children 6b37e6ddd302
comparison
equal deleted inserted replaced
154:94141801dd7e 155:43dd3413c7c7
2 ;; 2 ;;
3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc. 3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
4 ;; 4 ;;
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> 5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6 ;; Keywords: extensions 6 ;; Keywords: extensions
7 ;; Version: 1.98 7 ;; Version: 1.9907
8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ 8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
9 9
10 ;; This file is part of GNU Emacs. 10 ;; This file is part of GNU Emacs.
11 11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify 12 ;; GNU Emacs is free software; you can redistribute it and/or modify
29 ;; See `widget.el'. 29 ;; See `widget.el'.
30 30
31 ;;; Code: 31 ;;; Code:
32 32
33 (require 'widget) 33 (require 'widget)
34 (require 'cl) 34 (eval-when-compile (require 'cl))
35 35
36 ;;; Compatibility. 36 ;;; Compatibility.
37 37
38 (eval-and-compile 38 (eval-and-compile
39 (autoload 'pp-to-string "pp") 39 (autoload 'pp-to-string "pp")
42 (when (string-match "XEmacs" emacs-version) 42 (when (string-match "XEmacs" emacs-version)
43 (condition-case nil 43 (condition-case nil
44 (require 'overlay) 44 (require 'overlay)
45 (error (load-library "x-overlay")))) 45 (error (load-library "x-overlay"))))
46 46
47 (if (string-match "XEmacs" emacs-version)
48 ;; XEmacs spell `intangible' as `atomic'.
49 (defun widget-make-intangible (from to side)
50 "Make text between FROM and TO atomic with regard to movement.
51 Third argument should be `start-open' if it should be sticky to the rear,
52 and `end-open' if it should sticky to the front."
53 (require 'atomic-extents)
54 (let ((ext (make-extent from to)))
55 ;; XEmacs doesn't understant different kinds of read-only, so
56 ;; we have to use extents instead.
57 (put-text-property from to 'read-only nil)
58 (set-extent-property ext 'read-only t)
59 (set-extent-property ext 'start-open nil)
60 (set-extent-property ext 'end-open nil)
61 (set-extent-property ext side t)
62 (set-extent-property ext 'atomic t)))
63 (defun widget-make-intangible (from to size)
64 "Make text between FROM and TO intangible."
65 (put-text-property from to 'intangible 'front)))
66
67 (if (string-match "XEmacs" emacs-version) 47 (if (string-match "XEmacs" emacs-version)
68 (defun widget-event-point (event) 48 (defun widget-event-point (event)
69 "Character position of the end of event if that exists, or nil." 49 "Character position of the end of event if that exists, or nil."
70 (if (mouse-event-p event) 50 (if (mouse-event-p event)
71 (event-point event) 51 (event-point event)
72 nil)) 52 nil))
73 (defun widget-event-point (event) 53 (defun widget-event-point (event)
74 "Character position of the end of event if that exists, or nil." 54 "Character position of the end of event if that exists, or nil."
75 (posn-point (event-end event)))) 55 (posn-point (event-end event))))
76 56
77 ;; The following should go away when bundled with Emacs. 57 (defalias 'widget-read-event (if (string-match "XEmacs" emacs-version)
58 'next-event
59 'read-event))
60
61 ;; The following should go away when bundled with Emacs.
78 (condition-case () 62 (condition-case ()
79 (require 'custom) 63 (require 'custom)
80 (error nil)) 64 (error nil))
81 65
82 (unless (and (featurep 'custom) (fboundp 'custom-declare-variable)) 66 (unless (and (featurep 'custom) (fboundp 'custom-declare-variable))
107 (let ((buf (get-buffer-create " *error-message*"))) 91 (let ((buf (get-buffer-create " *error-message*")))
108 (erase-buffer buf) 92 (erase-buffer buf)
109 (display-error obj buf) 93 (display-error obj buf)
110 (buffer-string buf))))) 94 (buffer-string buf)))))
111 95
96 (when (let ((a "foo"))
97 (put-text-property 1 2 'foo 1 a)
98 (put-text-property 1 2 'bar 2 a)
99 (set-text-properties 1 2 nil a)
100 (text-properties-at 1 a))
101 ;; XEmacs 20.2 and earlier had a buggy set-text-properties.
102 (defun set-text-properties (start end props &optional buffer-or-string)
103 "Completely replace properties of text from START to END.
104 The third argument PROPS is the new property list.
105 The optional fourth argument, BUFFER-OR-STRING,
106 is the string or buffer containing the text."
107 (map-extents #'(lambda (extent ignored)
108 (remove-text-properties
109 start end
110 (list (extent-property extent 'text-prop)
111 nil)
112 buffer-or-string)
113 nil)
114 buffer-or-string start end nil nil 'text-prop)
115 (add-text-properties start end props buffer-or-string)))
116
112 ;;; Customization. 117 ;;; Customization.
113 118
114 (defgroup widgets nil 119 (defgroup widgets nil
115 "Customization support for the Widget Library." 120 "Customization support for the Widget Library."
116 :link '(custom-manual "(widget)Top") 121 :link '(custom-manual "(widget)Top")
118 "http://www.dina.kvl.dk/~abraham/custom/") 123 "http://www.dina.kvl.dk/~abraham/custom/")
119 :prefix "widget-" 124 :prefix "widget-"
120 :group 'extensions 125 :group 'extensions
121 :group 'faces 126 :group 'faces
122 :group 'hypermedia) 127 :group 'hypermedia)
123
124 (defface widget-documentation-face '((((class color)
125 (background dark))
126 (:foreground "lime green"))
127 (((class color)
128 (background light))
129 (:foreground "dark green"))
130 (t nil))
131 "Face used for documentation text."
132 :group 'widgets)
133 128
134 (defface widget-button-face '((t (:bold t))) 129 (defface widget-button-face '((t (:bold t)))
135 "Face used for widget buttons." 130 "Face used for widget buttons."
136 :group 'widgets) 131 :group 'widgets)
137 132
223 (listp (event-object val)) 218 (listp (event-object val))
224 (stringp (car-safe (event-object val))) 219 (stringp (car-safe (event-object val)))
225 (car (event-object val)))) 220 (car (event-object val))))
226 (cdr (assoc val items)))) 221 (cdr (assoc val items))))
227 (t 222 (t
228 (setq items (remove-if 'stringp items)) 223 (setq items (widget-remove-if 'stringp items))
229 (let ((val (completing-read (concat title ": ") items nil t))) 224 (let ((val (completing-read (concat title ": ") items nil t)))
230 (if (stringp val) 225 (if (stringp val)
231 (let ((try (try-completion val items))) 226 (let ((try (try-completion val items)))
232 (when (stringp try) 227 (when (stringp try)
233 (setq val try)) 228 (setq val try))
234 (cdr (assoc val items))) 229 (cdr (assoc val items)))
235 nil))))) 230 nil)))))
236 231
232 (defun widget-remove-if (predictate list)
233 (let (result (tail list))
234 (while tail
235 (or (funcall predictate (car tail))
236 (setq result (cons (car tail) result)))
237 (setq tail (cdr tail)))
238 (nreverse result)))
239
237 ;;; Widget text specifications. 240 ;;; Widget text specifications.
238 ;; 241 ;;
239 ;; These functions are for specifying text properties. 242 ;; These functions are for specifying text properties.
240 243
241 (defun widget-specify-none (from to) 244 (defun widget-specify-none (from to)
244 247
245 (defun widget-specify-text (from to) 248 (defun widget-specify-text (from to)
246 ;; Default properties. 249 ;; Default properties.
247 (add-text-properties from to (list 'read-only t 250 (add-text-properties from to (list 'read-only t
248 'front-sticky t 251 'front-sticky t
249 'start-open t 252 'rear-nonsticky nil
250 'end-open t 253 'start-open nil
251 'rear-nonsticky nil))) 254 'end-open nil)))
252 255
253 (defun widget-specify-field (widget from to) 256 (defun widget-specify-field (widget from to)
254 ;; Specify editable button for WIDGET between FROM and TO. 257 "Specify editable button for WIDGET between FROM and TO."
255 (widget-specify-field-update widget from to) 258 (put-text-property from to 'read-only nil)
256 259 ;; Terminating space is not part of the field, but necessary in
257 ;; Make it possible to edit the front end of the field. 260 ;; order for local-map to work. Remove next sexp if local-map works
258 (add-text-properties (1- from) from (list 'rear-nonsticky t 261 ;; at the end of the overlay.
259 'end-open t 262 (save-excursion
260 'invisible t)) 263 (goto-char to)
261 (when (or (string-match "\\(.\\|\n\\)%v" (widget-get widget :format)) 264 (insert-and-inherit " ")
262 (widget-get widget :hide-front-space)) 265 (setq to (point)))
263 ;; WARNING: This is going to lose horrible if the character just 266 (add-text-properties (1- to) to ;to (1+ to)
264 ;; before the field can be modified (e.g. if it belongs to a 267 '(front-sticky nil start-open t read-only to))
265 ;; choice widget). We try to compensate by checking the format 268 (add-text-properties (1- from) from
266 ;; string, and hope the user hasn't changed the :create method. 269 '(rear-nonsticky t end-open t read-only from))
267 (widget-make-intangible (- from 2) from 'end-open))
268
269 ;; Make it possible to edit back end of the field.
270 (add-text-properties to (1+ to) (list 'front-sticky nil
271 'read-only t
272 'start-open t))
273
274 (cond ((widget-get widget :size)
275 (put-text-property to (1+ to) 'invisible t)
276 (when (or (string-match "%v\\(.\\|\n\\)" (widget-get widget :format))
277 (widget-get widget :hide-rear-space))
278 ;; WARNING: This is going to lose horrible if the character just
279 ;; after the field can be modified (e.g. if it belongs to a
280 ;; choice widget). We try to compensate by checking the format
281 ;; string, and hope the user hasn't changed the :create method.
282 (widget-make-intangible to (+ to 2) 'start-open)))
283 ((string-match "XEmacs" emacs-version)
284 ;; XEmacs does not allow you to insert before a read-only
285 ;; character, even if it is start.open.
286 ;; XEmacs does allow you to delete an read-only extent, so
287 ;; making the terminating newline read only doesn't help.
288 ;; I tried putting an invisible intangible read-only space
289 ;; before the newline, which gave really weird effects.
290 ;; So for now, we just have trust the user not to delete the
291 ;; newline.
292 (put-text-property to (1+ to) 'read-only nil))))
293
294 (defun widget-specify-field-update (widget from to)
295 ;; Specify editable button for WIDGET between FROM and TO.
296 (let ((map (widget-get widget :keymap)) 270 (let ((map (widget-get widget :keymap))
297 (secret (widget-get widget :secret)) 271 (face (or (widget-get widget :value-face) 'widget-field-face))
298 (secret-to to)
299 (size (widget-get widget :size))
300 (face (or (widget-get widget :value-face)
301 'widget-field-face))
302 (help-echo (widget-get widget :help-echo)) 272 (help-echo (widget-get widget :help-echo))
303 (help-property (if (featurep 'balloon-help) 273 (overlay (make-overlay from to nil nil t)))
304 'balloon-help
305 'help-echo)))
306 (unless (or (stringp help-echo) (null help-echo)) 274 (unless (or (stringp help-echo) (null help-echo))
307 (setq help-echo 'widget-mouse-help)) 275 (setq help-echo 'widget-mouse-help))
308 276 (widget-put widget :field-overlay overlay)
309 (when secret 277 (overlay-put overlay 'detachable nil)
310 (while (and size 278 (overlay-put overlay 'field widget)
311 (not (zerop size)) 279 (overlay-put overlay 'local-map map)
312 (> secret-to from) 280 (overlay-put overlay 'keymap map)
313 (eq (char-after (1- secret-to)) ?\ )) 281 (overlay-put overlay 'face face)
314 (setq secret-to (1- secret-to))) 282 (overlay-put overlay 'balloon-help help-echo)
315 283 (overlay-put overlay 'help-echo help-echo)))
316 (save-excursion
317 (goto-char from)
318 (while (< (point) secret-to)
319 (let ((old (get-text-property (point) 'secret)))
320 (when old
321 (subst-char-in-region (point) (1+ (point)) secret old)))
322 (forward-char))))
323
324 (set-text-properties from to (list 'field widget
325 'read-only nil
326 'keymap map
327 'local-map map
328 help-property help-echo
329 'face face))
330
331 (when secret
332 (save-excursion
333 (goto-char from)
334 (while (< (point) secret-to)
335 (let ((old (following-char)))
336 (subst-char-in-region (point) (1+ (point)) old secret)
337 (put-text-property (point) (1+ (point)) 'secret old))
338 (forward-char))))
339
340 (unless (widget-get widget :size)
341 (add-text-properties to (1+ to) (list 'field widget
342 help-property help-echo
343 'face face)))
344 (add-text-properties to (1+ to) (list 'local-map map
345 'keymap map))))
346 284
347 (defun widget-specify-button (widget from to) 285 (defun widget-specify-button (widget from to)
348 ;; Specify button for WIDGET between FROM and TO. 286 "Specify button for WIDGET between FROM and TO."
349 (let ((face (widget-apply widget :button-face-get)) 287 (let ((face (widget-apply widget :button-face-get))
350 (help-echo (widget-get widget :help-echo)) 288 (help-echo (widget-get widget :help-echo))
351 (help-property (if (featurep 'balloon-help) 289 (overlay (make-overlay from to nil t nil)))
352 'balloon-help 290 (widget-put widget :button-overlay overlay)
353 'help-echo)))
354 (unless (or (null help-echo) (stringp help-echo)) 291 (unless (or (null help-echo) (stringp help-echo))
355 (setq help-echo 'widget-mouse-help)) 292 (setq help-echo 'widget-mouse-help))
356 (add-text-properties from to (list 'button widget 293 (overlay-put overlay 'button widget)
357 'mouse-face widget-mouse-face 294 (overlay-put overlay 'mouse-face widget-mouse-face)
358 'start-open t 295 (overlay-put overlay 'balloon-help help-echo)
359 'end-open t 296 (overlay-put overlay 'help-echo help-echo)
360 help-property help-echo 297 (overlay-put overlay 'face face)))
361 'face face))))
362 298
363 (defun widget-mouse-help (extent) 299 (defun widget-mouse-help (extent)
364 "Find mouse help string for button in extent." 300 "Find mouse help string for button in extent."
365 (let* ((widget (widget-at (extent-start-position extent))) 301 (let* ((widget (widget-at (extent-start-position extent)))
366 (help-echo (and widget (widget-get widget :help-echo)))) 302 (help-echo (and widget (widget-get widget :help-echo))))
416 (defun widget-specify-inactive (widget from to) 352 (defun widget-specify-inactive (widget from to)
417 "Make WIDGET inactive for user modifications." 353 "Make WIDGET inactive for user modifications."
418 (unless (widget-get widget :inactive) 354 (unless (widget-get widget :inactive)
419 (let ((overlay (make-overlay from to nil t nil))) 355 (let ((overlay (make-overlay from to nil t nil)))
420 (overlay-put overlay 'face 'widget-inactive-face) 356 (overlay-put overlay 'face 'widget-inactive-face)
357 (overlay-put overlay 'mouse-face 'widget-inactive-face)
421 (overlay-put overlay 'evaporate t) 358 (overlay-put overlay 'evaporate t)
422 (overlay-put overlay 'priority 100) 359 (overlay-put overlay 'priority 100)
423 (overlay-put overlay (if (string-match "XEmacs" emacs-version) 360 (overlay-put overlay (if (string-match "XEmacs" emacs-version)
424 'read-only 361 'read-only
425 'modification-hooks) '(widget-overlay-inactive)) 362 'modification-hooks) '(widget-overlay-inactive))
499 (cons (list (car vals)) (cdr vals))) 436 (cons (list (car vals)) (cdr vals)))
500 (t nil))) 437 (t nil)))
501 438
502 (defun widget-apply-action (widget &optional event) 439 (defun widget-apply-action (widget &optional event)
503 "Apply :action in WIDGET in response to EVENT." 440 "Apply :action in WIDGET in response to EVENT."
504 (if (widget-apply widget :active) 441 (let (after-change-functions)
505 (widget-apply widget :action event) 442 (if (widget-apply widget :active)
506 (error "Attempt to perform action on inactive widget"))) 443 (widget-apply widget :action event)
444 (error "Attempt to perform action on inactive widget"))))
507 445
508 ;;; Helper functions. 446 ;;; Helper functions.
509 ;; 447 ;;
510 ;; These are widget specific. 448 ;; These are widget specific.
511 449
558 :type '(repeat (cons :format "%v" 496 :type '(repeat (cons :format "%v"
559 (symbol :tag "Image Format" unknown) 497 (symbol :tag "Image Format" unknown)
560 (repeat :tag "Suffixes" 498 (repeat :tag "Suffixes"
561 (string :format "%v"))))) 499 (string :format "%v")))))
562 500
563 (defun widget-glyph-insert (widget tag image) 501 (defun widget-glyph-find (image tag)
564 "In WIDGET, insert the text TAG or, if supported, IMAGE. 502 "Create a glyph corresponding to IMAGE with string TAG as fallback.
565 IMAGE should either be a glyph, an image instantiator, or an image file 503 IMAGE should either already be a glyph, or be a file name sans
566 name sans extension (xpm, xbm, gif, jpg, or png) located in 504 extension (xpm, xbm, gif, jpg, or png) located in
567 `widget-glyph-directory'. 505 `widget-glyph-directory'."
568 506 (cond ((not (and image
569 WARNING: If you call this with a glyph, and you want the user to be 507 (string-match "XEmacs" emacs-version)
570 able to activate the glyph, make sure it is unique. If you use the
571 same glyph for multiple widgets, activating any of the glyphs will
572 cause the last created widget to be activated."
573 (cond ((not (and (string-match "XEmacs" emacs-version)
574 widget-glyph-enable 508 widget-glyph-enable
575 (fboundp 'make-glyph) 509 (fboundp 'make-glyph)
576 (fboundp 'locate-file) 510 (fboundp 'locate-file)
577 image)) 511 image))
578 ;; We don't want or can't use glyphs. 512 ;; We don't want or can't use glyphs.
579 (insert tag)) 513 nil)
580 ((and (fboundp 'glyphp) 514 ((and (fboundp 'glyphp)
581 (glyphp image)) 515 (glyphp image))
582 ;; Already a glyph. Insert it. 516 ;; Already a glyph. Use it.
583 (widget-glyph-insert-glyph widget image)) 517 image)
584 ((stringp image) 518 ((stringp image)
585 ;; A string. Look it up in relevant directories. 519 ;; A string. Look it up in relevant directories.
586 (let* ((dirlist (list (or widget-glyph-directory 520 (let* ((dirlist (list (or widget-glyph-directory
587 (concat data-directory 521 (concat data-directory
588 "custom/")) 522 "custom/"))
590 (formats widget-image-conversion) 524 (formats widget-image-conversion)
591 file) 525 file)
592 (while (and formats (not file)) 526 (while (and formats (not file))
593 (when (valid-image-instantiator-format-p (car (car formats))) 527 (when (valid-image-instantiator-format-p (car (car formats)))
594 (setq file (locate-file image dirlist 528 (setq file (locate-file image dirlist
595 (mapconcat 'identity (cdr (car formats)) 529 (mapconcat 'identity
530 (cdr (car formats))
596 ":")))) 531 ":"))))
597 (setq formats (cdr formats))) 532 (unless file
598 ;; We create a glyph with the file as the default image 533 (setq formats (cdr formats))))
599 ;; instantiator, and the TAG fallback 534 (and file
600 (widget-glyph-insert-glyph 535 ;; We create a glyph with the file as the default image
601 widget 536 ;; instantiator, and the TAG fallback
602 (make-glyph (if file 537 (make-glyph (list (vector (car (car formats)) ':file file)
603 (list (vector (car (car formats)) ':file file) 538 (vector 'string ':data tag))))))
604 (vector 'string ':data tag))
605 (vector 'string ':data tag))))))
606 ((valid-instantiator-p image 'image) 539 ((valid-instantiator-p image 'image)
607 ;; A valid image instantiator (e.g. [gif ':file "somefile"] etc.) 540 ;; A valid image instantiator (e.g. [gif :file "somefile"] etc.)
608 (widget-glyph-insert-glyph widget 541 (make-glyph (list image
609 (list image 542 (vector 'string ':data tag))))
610 (vector 'string ':data tag)))) 543 ((consp image)
544 ;; This could be virtually anything. Let `make-glyph' sort it out.
545 (make-glyph image))
611 (t 546 (t
612 ;; Oh well. 547 ;; Oh well.
613 (insert tag)))) 548 nil)))
549
550 (defun widget-glyph-insert (widget tag image &optional down inactive)
551 "In WIDGET, insert the text TAG or, if supported, IMAGE.
552 IMAGE should either be a glyph, an image instantiator, or an image file
553 name sans extension (xpm, xbm, gif, jpg, or png) located in
554 `widget-glyph-directory'.
555
556 Optional arguments DOWN and INACTIVE is used instead of IMAGE when the
557 glyph is pressed or inactive, respectively.
558
559 WARNING: If you call this with a glyph, and you want the user to be
560 able to invoke the glyph, make sure it is unique. If you use the
561 same glyph for multiple widgets, invoking any of the glyphs will
562 cause the last created widget to be invoked.
563
564 Instead of an instantiator, you can also use a list of instantiators,
565 or whatever `make-glyph' will accept. However, in that case you must
566 provide the fallback TAG as a part of the instantiator yourself."
567 (let ((glyph (widget-glyph-find image tag)))
568 (if glyph
569 (widget-glyph-insert-glyph widget
570 glyph
571 (widget-glyph-find down tag)
572 (widget-glyph-find inactive tag))
573 (insert tag))))
614 574
615 (defun widget-glyph-insert-glyph (widget glyph &optional down inactive) 575 (defun widget-glyph-insert-glyph (widget glyph &optional down inactive)
616 "In WIDGET, with alternative text TAG, insert GLYPH." 576 "In WIDGET, insert GLYPH.
577 If optional arguments DOWN and INACTIVE are given, they should be
578 glyphs used when the widget is pushed and inactive, respectively."
617 (set-glyph-property glyph 'widget widget) 579 (set-glyph-property glyph 'widget widget)
618 (when down 580 (when down
619 (set-glyph-property down 'widget widget)) 581 (set-glyph-property down 'widget widget))
620 (when inactive 582 (when inactive
621 (set-glyph-property inactive 'widget widget)) 583 (set-glyph-property inactive 'widget widget))
622 (insert "*") 584 (insert "*")
623 (add-text-properties (1- (point)) (point) 585 (let ((ext (make-extent (point) (1- (point))))
624 (list 'invisible t 586 (help-echo (widget-get widget :help-echo)))
625 'end-glyph glyph)) 587 (set-extent-property ext 'invisible t)
588 (set-extent-end-glyph ext glyph)
589 (when help-echo
590 (set-extent-property ext 'balloon-help help-echo)
591 (set-extent-property ext 'help-echo help-echo)))
626 (widget-put widget :glyph-up glyph) 592 (widget-put widget :glyph-up glyph)
627 (when down (widget-put widget :glyph-down down)) 593 (when down (widget-put widget :glyph-down down))
628 (when inactive (widget-put widget :glyph-inactive inactive)) 594 (when inactive (widget-put widget :glyph-inactive inactive)))
629 (let ((help-echo (widget-get widget :help-echo)))
630 (when help-echo
631 (let ((extent (extent-at (1- (point)) nil 'end-glyph))
632 (help-property (if (featurep 'balloon-help)
633 'balloon-help
634 'help-echo)))
635 (set-extent-property extent help-property (if (stringp help-echo)
636 help-echo
637 'widget-mouse-help))))))
638 595
639 ;;; Buttons. 596 ;;; Buttons.
640 597
641 (defgroup widget-button nil 598 (defgroup widget-button nil
642 "The look of various kinds of buttons." 599 "The look of various kinds of buttons."
643 :group 'widgets) 600 :group 'widgets)
644 601
645 (defcustom widget-button-prefix "" 602 (defcustom widget-button-prefix ""
646 "String used as prefix for buttons." 603 "String used as prefix for buttons."
647 :type 'string 604 :type 'string
648 :group 'widgets) 605 :group 'widget-button)
649 606
650 (defcustom widget-button-suffix "" 607 (defcustom widget-button-suffix ""
651 "String used as suffix for buttons." 608 "String used as suffix for buttons."
652 :type 'string 609 :type 'string
653 :group 'widgets) 610 :group 'widget-button)
654 611
655 (defun widget-button-insert-indirect (widget key) 612 (defun widget-button-insert-indirect (widget key)
656 "Insert value of WIDGET's KEY property." 613 "Insert value of WIDGET's KEY property."
657 (let ((val (widget-get widget key))) 614 (let ((val (widget-get widget key)))
658 (while (and val (symbolp val)) 615 (while (and val (symbolp val))
769 "Keymap containing useful binding for buffers containing widgets. 726 "Keymap containing useful binding for buffers containing widgets.
770 Recommended as a parent keymap for modes using widgets.") 727 Recommended as a parent keymap for modes using widgets.")
771 728
772 (unless widget-keymap 729 (unless widget-keymap
773 (setq widget-keymap (make-sparse-keymap)) 730 (setq widget-keymap (make-sparse-keymap))
774 (define-key widget-keymap "\C-k" 'widget-kill-line)
775 (define-key widget-keymap "\t" 'widget-forward) 731 (define-key widget-keymap "\t" 'widget-forward)
776 (define-key widget-keymap "\M-\t" 'widget-backward)
777 (define-key widget-keymap [(shift tab)] 'widget-backward) 732 (define-key widget-keymap [(shift tab)] 'widget-backward)
778 (define-key widget-keymap [backtab] 'widget-backward) 733 (define-key widget-keymap [backtab] 'widget-backward)
779 (if (string-match "XEmacs" emacs-version) 734 (if (string-match "XEmacs" emacs-version)
780 (progn 735 (progn
781 ;;Glyph support. 736 ;;Glyph support.
793 748
794 (unless widget-field-keymap 749 (unless widget-field-keymap
795 (setq widget-field-keymap (copy-keymap widget-keymap)) 750 (setq widget-field-keymap (copy-keymap widget-keymap))
796 (unless (string-match "XEmacs" (emacs-version)) 751 (unless (string-match "XEmacs" (emacs-version))
797 (define-key widget-field-keymap [menu-bar] 'nil)) 752 (define-key widget-field-keymap [menu-bar] 'nil))
753 (define-key widget-field-keymap "\C-k" 'widget-kill-line)
754 (define-key widget-field-keymap "\M-\t" 'widget-complete)
798 (define-key widget-field-keymap "\C-m" 'widget-field-activate) 755 (define-key widget-field-keymap "\C-m" 'widget-field-activate)
799 (define-key widget-field-keymap "\C-a" 'widget-beginning-of-line) 756 (define-key widget-field-keymap "\C-a" 'widget-beginning-of-line)
800 (define-key widget-field-keymap "\C-e" 'widget-end-of-line) 757 (define-key widget-field-keymap "\C-e" 'widget-end-of-line)
801 (set-keymap-parent widget-field-keymap global-map)) 758 (set-keymap-parent widget-field-keymap global-map))
802 759
810 (define-key widget-text-keymap "\C-a" 'widget-beginning-of-line) 767 (define-key widget-text-keymap "\C-a" 'widget-beginning-of-line)
811 (define-key widget-text-keymap "\C-e" 'widget-end-of-line) 768 (define-key widget-text-keymap "\C-e" 'widget-end-of-line)
812 (set-keymap-parent widget-text-keymap global-map)) 769 (set-keymap-parent widget-text-keymap global-map))
813 770
814 (defun widget-field-activate (pos &optional event) 771 (defun widget-field-activate (pos &optional event)
815 "Activate the ediable field at point." 772 "Invoke the ediable field at point."
816 (interactive "@d") 773 (interactive "@d")
817 (let ((field (get-text-property pos 'field))) 774 (let ((field (get-char-property pos 'field)))
818 (if field 775 (if field
819 (widget-apply-action field event) 776 (widget-apply-action field event)
820 (call-interactively 777 (call-interactively
821 (lookup-key widget-global-map (this-command-keys)))))) 778 (lookup-key widget-global-map (this-command-keys))))))
822 779
827 (:bold t :underline t))) 784 (:bold t :underline t)))
828 "Face used for pressed buttons." 785 "Face used for pressed buttons."
829 :group 'widgets) 786 :group 'widgets)
830 787
831 (defun widget-button-click (event) 788 (defun widget-button-click (event)
832 "Activate button below mouse pointer." 789 "Invoke button below mouse pointer."
833 (interactive "@e") 790 (interactive "@e")
834 (cond ((and (fboundp 'event-glyph) 791 (cond ((and (fboundp 'event-glyph)
835 (event-glyph event)) 792 (event-glyph event))
836 (widget-glyph-click event)) 793 (widget-glyph-click event))
837 ((widget-event-point event) 794 ((widget-event-point event)
838 (let* ((pos (widget-event-point event)) 795 (let* ((pos (widget-event-point event))
839 (button (get-text-property pos 'button))) 796 (button (get-char-property pos 'button)))
840 (if button 797 (if button
841 (let ((begin (previous-single-property-change (1+ pos) 'button)) 798 (let* ((overlay (widget-get button :button-overlay))
842 (end (next-single-property-change pos 'button)) 799 (face (overlay-get overlay 'face))
843 overlay) 800 (mouse-face (overlay-get overlay 'mouse-face)))
844 (unwind-protect 801 (unwind-protect
845 (let ((track-mouse t)) 802 (let ((track-mouse t))
846 (setq overlay (make-overlay begin end)) 803 (overlay-put overlay
847 (overlay-put overlay 'face 'widget-button-pressed-face) 804 'face 'widget-button-pressed-face)
848 (overlay-put overlay 805 (overlay-put overlay
849 'mouse-face 'widget-button-pressed-face) 806 'mouse-face 'widget-button-pressed-face)
850 (unless (widget-apply button :mouse-down-action event) 807 (unless (widget-apply button :mouse-down-action event)
851 (while (not (button-release-event-p event)) 808 (while (not (button-release-event-p event))
852 (setq event (if (fboundp 'read-event) 809 (setq event (widget-read-event)
853 (read-event)
854 (next-event))
855 pos (widget-event-point event)) 810 pos (widget-event-point event))
856 (if (and pos 811 (if (and pos
857 (eq (get-text-property pos 'button) 812 (eq (get-char-property pos 'button)
858 button)) 813 button))
859 (progn 814 (progn
860 (overlay-put overlay 815 (overlay-put overlay
861 'face 816 'face
862 'widget-button-pressed-face) 817 'widget-button-pressed-face)
863 (overlay-put overlay 818 (overlay-put overlay
864 'mouse-face 819 'mouse-face
865 'widget-button-pressed-face)) 820 'widget-button-pressed-face))
866 (overlay-put overlay 'face nil) 821 (overlay-put overlay 'face face)
867 (overlay-put overlay 'mouse-face nil)))) 822 (overlay-put overlay 'mouse-face mouse-face))))
868
869 (when (and pos 823 (when (and pos
870 (eq (get-text-property pos 'button) button)) 824 (eq (get-char-property pos 'button) button))
871 (widget-apply-action button event))) 825 (widget-apply-action button event)))
872 (delete-overlay overlay))) 826 (overlay-put overlay 'face face)
873 (call-interactively 827 (overlay-put overlay 'mouse-face mouse-face)))
874 (or (lookup-key widget-global-map [ button2 ]) 828 (let (command up)
875 (lookup-key widget-global-map [ down-mouse-2 ]) 829 ;; Find the global command to run, and check whether it
876 (lookup-key widget-global-map [ mouse-2])))))) 830 ;; is bound to an up event.
831 (cond ((setq command ;down event
832 (lookup-key widget-global-map [ button2 ])))
833 ((setq command ;down event
834 (lookup-key widget-global-map [ down-mouse-2 ])))
835 ((setq command ;up event
836 (lookup-key widget-global-map [ button2up ]))
837 (setq up t))
838 ((setq command ;up event
839 (lookup-key widget-global-map [ mouse-2]))
840 (setq up t)))
841 (when command
842 ;; Don't execute up events twice.
843 (when up
844 (while (not (button-release-event-p event))
845 (setq event (widget-read-event))))
846 (call-interactively command))))))
877 (t 847 (t
878 (message "You clicked somewhere weird.")))) 848 (message "You clicked somewhere weird."))))
879 849
880 (defun widget-button1-click (event) 850 (defun widget-button1-click (event)
881 "Activate glyph below mouse pointer." 851 "Invoke glyph below mouse pointer."
882 (interactive "@e") 852 (interactive "@e")
883 (if (and (fboundp 'event-glyph) 853 (if (and (fboundp 'event-glyph)
884 (event-glyph event)) 854 (event-glyph event))
885 (widget-glyph-click event) 855 (widget-glyph-click event)
886 (call-interactively (lookup-key widget-global-map (this-command-keys))))) 856 (call-interactively (lookup-key widget-global-map (this-command-keys)))))
911 (message "This glyph is inactive.")) 881 (message "This glyph is inactive."))
912 (t 882 (t
913 (widget-apply-action widget event))))))) 883 (widget-apply-action widget event)))))))
914 884
915 (defun widget-button-press (pos &optional event) 885 (defun widget-button-press (pos &optional event)
916 "Activate button at POS." 886 "Invoke button at POS."
917 (interactive "@d") 887 (interactive "@d")
918 (let ((button (get-text-property pos 'button))) 888 (let ((button (get-char-property pos 'button)))
919 (if button 889 (if button
920 (widget-apply-action button event) 890 (widget-apply-action button event)
921 (let ((command (lookup-key widget-global-map (this-command-keys)))) 891 (let ((command (lookup-key widget-global-map (this-command-keys))))
922 (when (commandp command) 892 (when (commandp command)
923 (call-interactively command)))))) 893 (call-interactively command))))))
924 894
925 (defun widget-move (arg) 895 (defun widget-move (arg)
926 "Move point to the ARG next field or button. 896 "Move point to the ARG next field or button.
927 ARG may be negative to move backward." 897 ARG may be negative to move backward."
928 (while (> arg 0) 898 (or (bobp) (> arg 0) (backward-char))
929 (setq arg (1- arg)) 899 (let ((pos (point))
930 (let ((next (cond ((get-text-property (point) 'button) 900 (number arg)
931 (next-single-property-change (point) 'button)) 901 (old (or (get-char-property (point) 'button)
932 ((get-text-property (point) 'field) 902 (get-char-property (point) 'field)))
933 (next-single-property-change (point) 'field)) 903 new)
934 (t 904 ;; Forward.
935 (point))))) 905 (while (> arg 0)
936 (if (null next) ; Widget extends to end. of buffer 906 (if (eobp)
937 (setq next (point-min))) 907 (goto-char (point-min))
938 (let ((button (next-single-property-change next 'button))
939 (field (next-single-property-change next 'field)))
940 (cond ((or (get-text-property next 'button)
941 (get-text-property next 'field))
942 (goto-char next))
943 ((and button field)
944 (goto-char (min button field)))
945 (button (goto-char button))
946 (field (goto-char field))
947 (t
948 (let ((button (next-single-property-change (point-min) 'button))
949 (field (next-single-property-change (point-min) 'field)))
950 (cond ((and button field) (goto-char (min button field)))
951 (button (goto-char button))
952 (field (goto-char field))
953 (t
954 (error "No buttons or fields found"))))))
955 (setq button (widget-at (point)))
956 (if (or (and button (widget-get button :tab-order)
957 (< (widget-get button :tab-order) 0))
958 (and button (not (widget-apply button :active))))
959 (setq arg (1+ arg))))))
960 (while (< arg 0)
961 (if (= (point-min) (point))
962 (forward-char 1)) 908 (forward-char 1))
963 (setq arg (1+ arg)) 909 (and (eq pos (point))
964 (let ((previous (cond ((get-text-property (1- (point)) 'button) 910 (eq arg number)
965 (previous-single-property-change (point) 'button)) 911 (error "No buttons or fields found"))
966 ((get-text-property (1- (point)) 'field) 912 (let ((new (or (get-char-property (point) 'button)
967 (previous-single-property-change (point) 'field)) 913 (get-char-property (point) 'field))))
968 (t 914 (when new
969 (point))))) 915 (unless (eq new old)
970 (if (null previous) ; Widget extends to beg. of buffer 916 (unless (and (widget-get new :tab-order)
971 (setq previous (point-max))) 917 (< (widget-get new :tab-order) 0))
972 (let ((button (previous-single-property-change previous 'button)) 918 (setq arg (1- arg)))
973 (field (previous-single-property-change previous 'field))) 919 (setq old new)))))
974 (cond ((and button field) 920 ;; Backward.
975 (goto-char (max button field))) 921 (while (< arg 0)
976 (button (goto-char button)) 922 (if (bobp)
977 (field (goto-char field)) 923 (goto-char (point-max))
978 (t 924 (backward-char 1))
979 (let ((button (previous-single-property-change 925 (and (eq pos (point))
980 (point-max) 'button)) 926 (eq arg number)
981 (field (previous-single-property-change 927 (error "No buttons or fields found"))
982 (point-max) 'field))) 928 (let ((new (or (get-char-property (point) 'button)
983 (cond ((and button field) (goto-char (max button field))) 929 (get-char-property (point) 'field))))
984 (button (goto-char button)) 930 (when new
985 (field (goto-char field)) 931 (unless (eq new old)
986 (t 932 (unless (and (widget-get new :tab-order)
987 (error "No buttons or fields found")))))))) 933 (< (widget-get new :tab-order) 0))
988 (let ((button (previous-single-property-change (point) 'button)) 934 (setq arg (1+ arg)))))))
989 (field (previous-single-property-change (point) 'field))) 935 (while (or (get-char-property (point) 'button)
990 (cond ((and button field) 936 (get-char-property (point) 'field))
991 (goto-char (max button field))) 937 (backward-char))
992 (button (goto-char button)) 938 (forward-char))
993 (field (goto-char field)))
994 (setq button (widget-at (point)))
995 (if (or (and button (widget-get button :tab-order)
996 (< (widget-get button :tab-order) 0))
997 (and button (not (widget-apply button :active))))
998 (setq arg (1- arg)))))
999 (widget-echo-help (point)) 939 (widget-echo-help (point))
1000 (run-hooks 'widget-move-hook)) 940 (run-hooks 'widget-move-hook))
1001 941
1002 (defun widget-forward (arg) 942 (defun widget-forward (arg)
1003 "Move point to the next field or button. 943 "Move point to the next field or button.
1014 (widget-move (- arg))) 954 (widget-move (- arg)))
1015 955
1016 (defun widget-beginning-of-line () 956 (defun widget-beginning-of-line ()
1017 "Go to beginning of field or beginning of line, whichever is first." 957 "Go to beginning of field or beginning of line, whichever is first."
1018 (interactive) 958 (interactive)
1019 (let ((bol (save-excursion (beginning-of-line) (point))) 959 (let* ((field (widget-field-find (point)))
1020 (prev (previous-single-property-change (point) 'field))) 960 (start (and field (widget-field-start field))))
1021 (goto-char (max bol (or prev bol))))) 961 (if (and start (not (eq start (point))))
962 (goto-char start)
963 (call-interactively 'beginning-of-line))))
1022 964
1023 (defun widget-end-of-line () 965 (defun widget-end-of-line ()
1024 "Go to end of field or end of line, whichever is first." 966 "Go to end of field or end of line, whichever is first."
1025 (interactive) 967 (interactive)
1026 (let ((bol (save-excursion (end-of-line) (point))) 968 (let* ((field (widget-field-find (point)))
1027 (prev (next-single-property-change (point) 'field))) 969 (end (and field (widget-field-end field))))
1028 (goto-char (min bol (or prev bol))))) 970 (if (and end (not (eq end (point))))
971 (goto-char end)
972 (call-interactively 'end-of-line))))
1029 973
1030 (defun widget-kill-line () 974 (defun widget-kill-line ()
1031 "Kill to end of field or end of line, whichever is first." 975 "Kill to end of field or end of line, whichever is first."
1032 (interactive) 976 (interactive)
1033 (let ((field (get-text-property (point) 'field)) 977 (let ((field (get-char-property (point) 'field))
1034 (newline (save-excursion (search-forward "\n"))) 978 (newline (save-excursion (forward-line 1)))
1035 (next (next-single-property-change (point) 'field))) 979 (next (next-single-property-change (point) 'field)))
1036 (if (and field (> newline next)) 980 (if (and field (> newline next))
1037 (kill-region (point) next) 981 (kill-region (point) next)
1038 (call-interactively 'kill-line)))) 982 (call-interactively 'kill-line))))
983
984 (defcustom widget-complete-field (lookup-key global-map "\M-\t")
985 "Default function to call for completion inside fields."
986 :options '(ispell-complete-word complete-tag lisp-complete-symbol)
987 :type 'function
988 :group 'widgets)
989
990 (defun widget-complete ()
991 "Complete content of editable field from point.
992 When not inside a field, move to the previous button or field."
993 (interactive)
994 (let ((field (widget-field-find (point))))
995 (if field
996 (widget-apply field :complete)
997 (error "Not in an editable field"))))
1039 998
1040 ;;; Setting up the buffer. 999 ;;; Setting up the buffer.
1041 1000
1042 (defvar widget-field-new nil) 1001 (defvar widget-field-new nil)
1043 ;; List of all newly created editable fields in the buffer. 1002 ;; List of all newly created editable fields in the buffer.
1054 field) 1013 field)
1055 (while widget-field-new 1014 (while widget-field-new
1056 (setq field (car widget-field-new) 1015 (setq field (car widget-field-new)
1057 widget-field-new (cdr widget-field-new) 1016 widget-field-new (cdr widget-field-new)
1058 widget-field-list (cons field widget-field-list)) 1017 widget-field-list (cons field widget-field-list))
1059 (let ((from (widget-get field :value-from)) 1018 (let ((from (car (widget-get field :field-overlay)))
1060 (to (widget-get field :value-to))) 1019 (to (cdr (widget-get field :field-overlay))))
1061 (widget-specify-field field from to) 1020 (widget-specify-field field from to)
1062 (move-marker from (1- from)) 1021 (set-marker from nil)
1063 (move-marker to (1+ to))))) 1022 (set-marker to nil))))
1064 (widget-clear-undo) 1023 (widget-clear-undo)
1065 ;; We need to maintain text properties and size of the editing fields. 1024 ;; We need to maintain text properties and size of the editing fields.
1066 (make-local-variable 'after-change-functions) 1025 (make-local-variable 'after-change-functions)
1067 (if widget-field-list 1026 (if (and widget-field-list)
1068 (setq after-change-functions '(widget-after-change)) 1027 (setq after-change-functions '(widget-after-change))
1069 (setq after-change-functions nil))) 1028 (setq after-change-functions nil)))
1070 1029
1071 (defvar widget-field-last nil) 1030 (defvar widget-field-last nil)
1072 ;; Last field containing point. 1031 ;; Last field containing point.
1074 1033
1075 (defvar widget-field-was nil) 1034 (defvar widget-field-was nil)
1076 ;; The widget data before the change. 1035 ;; The widget data before the change.
1077 (make-variable-buffer-local 'widget-field-was) 1036 (make-variable-buffer-local 'widget-field-was)
1078 1037
1038 (defun widget-field-buffer (widget)
1039 "Return the start of WIDGET's editing field."
1040 (overlay-buffer (widget-get widget :field-overlay)))
1041
1042 (defun widget-field-start (widget)
1043 "Return the start of WIDGET's editing field."
1044 (overlay-start (widget-get widget :field-overlay)))
1045
1046 (defun widget-field-end (widget)
1047 "Return the end of WIDGET's editing field."
1048 ;; Don't subtract one if local-map works at the end of the overlay.
1049 (1- (overlay-end (widget-get widget :field-overlay))))
1050
1079 (defun widget-field-find (pos) 1051 (defun widget-field-find (pos)
1080 ;; Find widget whose editing field is located at POS. 1052 "Return the field at POS.
1081 ;; Return nil if POS is not inside and editing field. 1053 Unlike (get-char-property POS 'field) this, works with empty fields too."
1082 ;;
1083 ;; This is only used in `widget-field-modified', since ordinarily
1084 ;; you would just test the field property.
1085 (let ((fields widget-field-list) 1054 (let ((fields widget-field-list)
1086 field found) 1055 field found)
1087 (while fields 1056 (while fields
1088 (setq field (car fields) 1057 (setq field (car fields)
1089 fields (cdr fields)) 1058 fields (cdr fields))
1090 (let ((from (widget-get field :value-from)) 1059 (let ((start (widget-field-start field))
1091 (to (widget-get field :value-to))) 1060 (end (widget-field-end field)))
1092 (if (and from to (< from pos) (> to pos)) 1061 (when (and (<= start pos) (<= pos end))
1093 (setq fields nil 1062 (when found
1094 found field)))) 1063 (debug "Overlapping fields"))
1064 (setq found field))))
1095 found)) 1065 found))
1096 1066
1097 (defun widget-after-change (from to old) 1067 (defun widget-after-change (from to old)
1098 ;; Adjust field size and text properties. 1068 ;; Adjust field size and text properties.
1099 (condition-case nil 1069 (condition-case nil
1100 (let ((field (widget-field-find from)) 1070 (let ((field (widget-field-find from))
1101 (inhibit-read-only t)) 1071 (other (widget-field-find to)))
1102 (cond ((null field)) 1072 (when field
1103 ((not (eq field (widget-field-find to))) 1073 (unless (eq field other)
1104 (debug) 1074 (debug "Change in different fields"))
1105 (message "Error: `widget-after-change' called on two fields")) 1075 (let ((size (widget-get field :size)))
1106 (t 1076 (when size
1107 (let ((size (widget-get field :size))) 1077 (let ((begin (widget-field-start field))
1108 (if size 1078 (end (widget-field-end field)))
1109 (let ((begin (1+ (widget-get field :value-from))) 1079 (cond ((< (- end begin) size)
1110 (end (1- (widget-get field :value-to)))) 1080 ;; Field too small.
1111 (widget-specify-field-update field begin end) 1081 (save-excursion
1112 (cond ((< (- end begin) size) 1082 (goto-char end)
1113 ;; Field too small. 1083 (insert-char ?\ (- (+ begin size) end))))
1114 (save-excursion 1084 ((> (- end begin) size)
1115 (goto-char end) 1085 ;; Field too large and
1116 (insert-char ?\ (- (+ begin size) end)) 1086 (if (or (< (point) (+ begin size))
1117 (widget-specify-field-update field 1087 (> (point) end))
1118 begin 1088 ;; Point is outside extra space.
1119 (+ begin size)))) 1089 (setq begin (+ begin size))
1120 ((> (- end begin) size) 1090 ;; Point is within the extra space.
1121 ;; Field too large and 1091 (setq begin (point)))
1122 (if (or (< (point) (+ begin size)) 1092 (save-excursion
1123 (> (point) end)) 1093 (goto-char end)
1124 ;; Point is outside extra space. 1094 (while (and (eq (preceding-char) ?\ )
1125 (setq begin (+ begin size)) 1095 (> (point) begin))
1126 ;; Point is within the extra space. 1096 (delete-backward-char 1))))))))
1127 (setq begin (point))) 1097 (widget-apply field :notify field)))
1128 (save-excursion 1098 (error (debug "After Change"))))
1129 (goto-char end)
1130 (while (and (eq (preceding-char) ?\ )
1131 (> (point) begin))
1132 (delete-backward-char 1))))))
1133 (widget-specify-field-update field from to)))
1134 (widget-apply field :notify field))))
1135 (error (debug))))
1136 1099
1137 ;;; Widget Functions 1100 ;;; Widget Functions
1138 ;; 1101 ;;
1139 ;; These functions are used in the definition of multiple widgets. 1102 ;; These functions are used in the definition of multiple widgets.
1140 1103
1186 "Basic widget other widgets are derived from." 1149 "Basic widget other widgets are derived from."
1187 :value-to-internal (lambda (widget value) value) 1150 :value-to-internal (lambda (widget value) value)
1188 :value-to-external (lambda (widget value) value) 1151 :value-to-external (lambda (widget value) value)
1189 :button-prefix 'widget-button-prefix 1152 :button-prefix 'widget-button-prefix
1190 :button-suffix 'widget-button-suffix 1153 :button-suffix 'widget-button-suffix
1154 :complete 'widget-default-complete
1191 :create 'widget-default-create 1155 :create 'widget-default-create
1192 :indent nil 1156 :indent nil
1193 :offset 0 1157 :offset 0
1194 :format-handler 'widget-default-format-handler 1158 :format-handler 'widget-default-format-handler
1195 :button-face-get 'widget-default-button-face-get 1159 :button-face-get 'widget-default-button-face-get
1204 :deactivate 'widget-default-deactivate 1168 :deactivate 'widget-default-deactivate
1205 :mouse-down-action (lambda (widget event) nil) 1169 :mouse-down-action (lambda (widget event) nil)
1206 :action 'widget-default-action 1170 :action 'widget-default-action
1207 :notify 'widget-default-notify 1171 :notify 'widget-default-notify
1208 :prompt-value 'widget-default-prompt-value) 1172 :prompt-value 'widget-default-prompt-value)
1173
1174 (defun widget-default-complete (widget)
1175 "Call the value of the :complete-function property of WIDGET.
1176 If that does not exists, call the value of `widget-complete-field'."
1177 (let ((fun (widget-get widget :complete-function)))
1178 (call-interactively (or fun widget-complete-field))))
1209 1179
1210 (defun widget-default-create (widget) 1180 (defun widget-default-create (widget)
1211 "Create WIDGET at point in the current buffer." 1181 "Create WIDGET at point in the current buffer."
1212 (widget-specify-insert 1182 (widget-specify-insert
1213 (let ((from (point)) 1183 (let ((from (point))
1303 (when (eq (aref doc-text 0) ?*) 1273 (when (eq (aref doc-text 0) ?*)
1304 (setq doc-text (substring doc-text 1))) 1274 (setq doc-text (substring doc-text 1)))
1305 ;; Get rid of trailing newlines. 1275 ;; Get rid of trailing newlines.
1306 (when (string-match "\n+\\'" doc-text) 1276 (when (string-match "\n+\\'" doc-text)
1307 (setq doc-text (substring doc-text 0 (match-beginning 0)))) 1277 (setq doc-text (substring doc-text 0 (match-beginning 0))))
1308 (push (if (string-match "\n." doc-text) 1278 (push (widget-create-child-and-convert
1309 ;; Allow multiline doc to be hiden. 1279 widget 'documentation-string
1310 (widget-create-child-and-convert 1280 doc-text)
1311 widget 'widget-help
1312 :doc (progn
1313 (string-match "\\`.*" doc-text)
1314 (match-string 0 doc-text))
1315 :widget-doc doc-text
1316 "?")
1317 ;; A single line is just inserted.
1318 (widget-create-child-and-convert
1319 widget 'item :format "%d" :doc doc-text nil))
1320 buttons))) 1281 buttons)))
1321 (t 1282 (t
1322 (error "Unknown escape `%c'" escape))) 1283 (error "Unknown escape `%c'" escape)))
1323 (widget-put widget :buttons buttons))) 1284 (widget-put widget :buttons buttons)))
1324 1285
1332 1293
1333 (defun widget-default-delete (widget) 1294 (defun widget-default-delete (widget)
1334 ;; Remove widget from the buffer. 1295 ;; Remove widget from the buffer.
1335 (let ((from (widget-get widget :from)) 1296 (let ((from (widget-get widget :from))
1336 (to (widget-get widget :to)) 1297 (to (widget-get widget :to))
1337 (inhibit-read-only t) 1298 (inactive-overlay (widget-get widget :inactive))
1338 after-change-functions) 1299 (button-overlay (widget-get widget :button-overlay))
1300 after-change-functions
1301 (inhibit-read-only t))
1339 (widget-apply widget :value-delete) 1302 (widget-apply widget :value-delete)
1303 (when inactive-overlay
1304 (delete-overlay inactive-overlay))
1305 (when button-overlay
1306 (delete-overlay button-overlay))
1340 (when (< from to) 1307 (when (< from to)
1341 ;; Kludge: this doesn't need to be true for empty formats. 1308 ;; Kludge: this doesn't need to be true for empty formats.
1342 (delete-region from to)) 1309 (delete-region from to))
1343 (set-marker from nil) 1310 (set-marker from nil)
1344 (set-marker to nil)) 1311 (set-marker to nil))
1420 (defun widget-item-match-inline (widget values) 1387 (defun widget-item-match-inline (widget values)
1421 ;; Match if the value is the same. 1388 ;; Match if the value is the same.
1422 (let ((value (widget-get widget :value))) 1389 (let ((value (widget-get widget :value)))
1423 (and (listp value) 1390 (and (listp value)
1424 (<= (length value) (length values)) 1391 (<= (length value) (length values))
1425 (let ((head (subseq values 0 (length value)))) 1392 (let ((head (widget-sublist values 0 (length value))))
1426 (and (equal head value) 1393 (and (equal head value)
1427 (cons head (subseq values (length value)))))))) 1394 (cons head (widget-sublist values (length value))))))))
1395
1396 (defun widget-sublist (list start &optional end)
1397 "Return the sublist of LIST from START to END.
1398 If END is omitted, it defaults to the length of LIST."
1399 (if (> start 0) (setq list (nthcdr start list)))
1400 (if end
1401 (if (<= end start)
1402 nil
1403 (setq list (copy-sequence list))
1404 (setcdr (nthcdr (- end start 1) list) nil)
1405 list)
1406 (copy-sequence list)))
1428 1407
1429 (defun widget-item-action (widget &optional event) 1408 (defun widget-item-action (widget &optional event)
1430 ;; Just notify itself. 1409 ;; Just notify itself.
1431 (widget-apply widget :notify widget event)) 1410 (widget-apply widget :notify widget event))
1432 1411
1490 "Apply :action for WIDGET." 1469 "Apply :action for WIDGET."
1491 (widget-apply-action widget (this-command-keys))) 1470 (widget-apply-action widget (this-command-keys)))
1492 1471
1493 ;;; The `link' Widget. 1472 ;;; The `link' Widget.
1494 1473
1495 (defcustom widget-link-prefix "_" 1474 (defcustom widget-link-prefix "["
1496 "String used as prefix for links." 1475 "String used as prefix for links."
1497 :type 'string 1476 :type 'string
1498 :group 'widget-button) 1477 :group 'widget-button)
1499 1478
1500 (defcustom widget-link-suffix "_" 1479 (defcustom widget-link-suffix "]"
1501 "String used as suffix for links." 1480 "String used as suffix for links."
1502 :type 'string 1481 :type 'string
1503 :group 'widget-button) 1482 :group 'widget-button)
1504 1483
1505 (define-widget 'link 'item 1484 (define-widget 'link 'item
1576 (let ((prompt (concat (widget-apply widget :menu-tag-get) ": ")) 1555 (let ((prompt (concat (widget-apply widget :menu-tag-get) ": "))
1577 (value (unless invalid 1556 (value (unless invalid
1578 (widget-value widget)))) 1557 (widget-value widget))))
1579 (let ((answer (widget-apply widget :prompt-value prompt value invalid) )) 1558 (let ((answer (widget-apply widget :prompt-value prompt value invalid) ))
1580 (widget-value-set widget answer))) 1559 (widget-value-set widget answer)))
1581 (widget-apply widget :notify widget event) 1560 (widget-setup)
1582 (widget-setup))) 1561 (widget-apply widget :notify widget event)))
1583 1562
1584 (defun widget-field-validate (widget) 1563 (defun widget-field-validate (widget)
1585 ;; Valid if the content matches `:valid-regexp'. 1564 ;; Valid if the content matches `:valid-regexp'.
1586 (save-excursion 1565 (save-excursion
1587 (let ((value (widget-apply widget :value-get)) 1566 (let ((value (widget-apply widget :value-get))
1590 nil 1569 nil
1591 widget)))) 1570 widget))))
1592 1571
1593 (defun widget-field-value-create (widget) 1572 (defun widget-field-value-create (widget)
1594 ;; Create an editable text field. 1573 ;; Create an editable text field.
1595 (insert " ")
1596 (let ((size (widget-get widget :size)) 1574 (let ((size (widget-get widget :size))
1597 (value (widget-get widget :value)) 1575 (value (widget-get widget :value))
1598 (from (point))) 1576 (from (point))
1577 (overlay (cons (make-marker) (make-marker))))
1578 (widget-put widget :field-overlay overlay)
1599 (insert value) 1579 (insert value)
1600 (and size 1580 (and size
1601 (< (length value) size) 1581 (< (length value) size)
1602 (insert-char ?\ (- size (length value)))) 1582 (insert-char ?\ (- size (length value))))
1603 (unless (memq widget widget-field-list) 1583 (unless (memq widget widget-field-list)
1604 (setq widget-field-new (cons widget widget-field-new))) 1584 (setq widget-field-new (cons widget widget-field-new)))
1605 (widget-put widget :value-to (copy-marker (point))) 1585 (move-marker (cdr overlay) (point))
1606 (set-marker-insertion-type (widget-get widget :value-to) nil) 1586 (set-marker-insertion-type (cdr overlay) nil)
1607 (if (null size) 1587 (when (null size)
1608 (insert ?\n) 1588 (insert ?\n))
1609 (insert ?\ )) 1589 (move-marker (car overlay) from)
1610 (widget-put widget :value-from (copy-marker from)) 1590 (set-marker-insertion-type (car overlay) t)))
1611 (set-marker-insertion-type (widget-get widget :value-from) t)))
1612 1591
1613 (defun widget-field-value-delete (widget) 1592 (defun widget-field-value-delete (widget)
1614 ;; Remove the widget from the list of active editing fields. 1593 ;; Remove the widget from the list of active editing fields.
1615 (setq widget-field-list (delq widget widget-field-list)) 1594 (setq widget-field-list (delq widget widget-field-list))
1616 ;; These are nil if the :format string doesn't contain `%v'. 1595 ;; These are nil if the :format string doesn't contain `%v'.
1617 (when (widget-get widget :value-from) 1596 (let ((overlay (widget-get widget :field-overlay)))
1618 (set-marker (widget-get widget :value-from) nil)) 1597 (when overlay
1619 (when (widget-get widget :value-from) 1598 (delete-overlay overlay))))
1620 (set-marker (widget-get widget :value-to) nil)))
1621 1599
1622 (defun widget-field-value-get (widget) 1600 (defun widget-field-value-get (widget)
1623 ;; Return current text in editing field. 1601 ;; Return current text in editing field.
1624 (let ((from (widget-get widget :value-from)) 1602 (let ((from (widget-field-start widget))
1625 (to (widget-get widget :value-to)) 1603 (to (widget-field-end widget))
1604 (buffer (widget-field-buffer widget))
1626 (size (widget-get widget :size)) 1605 (size (widget-get widget :size))
1627 (secret (widget-get widget :secret)) 1606 (secret (widget-get widget :secret))
1628 (old (current-buffer))) 1607 (old (current-buffer)))
1629 (if (and from to) 1608 (if (and from to)
1630 (progn 1609 (progn
1631 (set-buffer (marker-buffer from)) 1610 (set-buffer buffer)
1632 (setq from (1+ from)
1633 to (1- to))
1634 (while (and size 1611 (while (and size
1635 (not (zerop size)) 1612 (not (zerop size))
1636 (> to from) 1613 (> to from)
1637 (eq (char-after (1- to)) ?\ )) 1614 (eq (char-after (1- to)) ?\ ))
1638 (setq to (1- to))) 1615 (setq to (1- to)))
1639 (let ((result (buffer-substring-no-properties from to))) 1616 (let ((result (buffer-substring-no-properties from to)))
1640 (when (string-match "XEmacs" emacs-version)
1641 ;; XEmacs 20.1 bug: b-s-n-p doesn't clear all properties.
1642 (setq result (format "%s" result)))
1643 (when secret 1617 (when secret
1644 (let ((index 0)) 1618 (let ((index 0))
1645 (while (< (+ from index) to) 1619 (while (< (+ from index) to)
1646 (aset result index 1620 (aset result index
1647 (get-text-property (+ from index) 'secret)) 1621 (get-char-property (+ from index) 'secret))
1648 (setq index (1+ index))))) 1622 (setq index (1+ index)))))
1649 (set-buffer old) 1623 (set-buffer old)
1650 result)) 1624 result))
1651 (widget-get widget :value)))) 1625 (widget-get widget :value))))
1652 1626
1709 (widget-apply (car (widget-get widget :children)) :value-inline)) 1683 (widget-apply (car (widget-get widget :children)) :value-inline))
1710 1684
1711 (defcustom widget-choice-toggle nil 1685 (defcustom widget-choice-toggle nil
1712 "If non-nil, a binary choice will just toggle between the values. 1686 "If non-nil, a binary choice will just toggle between the values.
1713 Otherwise, the user will explicitly have to choose between the values 1687 Otherwise, the user will explicitly have to choose between the values
1714 when he activate the menu." 1688 when he invoked the menu."
1715 :type 'boolean 1689 :type 'boolean
1716 :group 'widgets) 1690 :group 'widgets)
1717 1691
1718 (defun widget-choice-mouse-down-action (widget &optional event) 1692 (defun widget-choice-mouse-down-action (widget &optional event)
1719 ;; Return non-nil if we need a menu. 1693 ;; Return non-nil if we need a menu.
1776 (widget-choose tag (reverse choices) event)))) 1750 (widget-choose tag (reverse choices) event))))
1777 (when current 1751 (when current
1778 (widget-value-set widget 1752 (widget-value-set widget
1779 (widget-apply current :value-to-external 1753 (widget-apply current :value-to-external
1780 (widget-get current :value))) 1754 (widget-get current :value)))
1781 (widget-apply widget :notify widget event) 1755 (widget-setup)
1782 (widget-setup)))) 1756 (widget-apply widget :notify widget event))))
1783 1757
1784 (defun widget-choice-validate (widget) 1758 (defun widget-choice-validate (widget)
1785 ;; Valid if we have made a valid choice. 1759 ;; Valid if we have made a valid choice.
1786 (let ((void (widget-get widget :void)) 1760 (let ((void (widget-get widget :void))
1787 (choice (widget-get widget :choice)) 1761 (choice (widget-get widget :choice))
2326 (widget-put widget :children (cons child children)) 2300 (widget-put widget :children (cons child children))
2327 (while (not (eq (car (cdr children)) before)) 2301 (while (not (eq (car (cdr children)) before))
2328 (setq children (cdr children))) 2302 (setq children (cdr children)))
2329 (setcdr children (cons child (cdr children))))))) 2303 (setcdr children (cons child (cdr children)))))))
2330 (widget-setup) 2304 (widget-setup)
2331 widget (widget-apply widget :notify widget)) 2305 (widget-apply widget :notify widget))
2332 2306
2333 (defun widget-editable-list-delete-at (widget child) 2307 (defun widget-editable-list-delete-at (widget child)
2334 ;; Delete child from list of children. 2308 ;; Delete child from list of children.
2335 (save-excursion 2309 (save-excursion
2336 (let ((buttons (copy-sequence (widget-get widget :buttons))) 2310 (let ((buttons (copy-sequence (widget-get widget :buttons)))
2458 args nil))) 2432 args nil)))
2459 (if answer 2433 (if answer
2460 (cons found vals) 2434 (cons found vals)
2461 nil))) 2435 nil)))
2462 2436
2463 ;;; The `widget-help' Widget. 2437 ;;; The `visibility' Widget.
2464 2438
2465 (define-widget 'widget-help 'push-button 2439 (define-widget 'visibility 'item
2466 "The widget documentation button." 2440 "An indicator and manipulator for hidden items."
2467 :format "%[%t%] %d" 2441 :format "%[%v%]"
2468 :help-echo "Toggle display of documentation." 2442 :button-prefix ""
2469 :action 'widget-help-action) 2443 :button-suffix ""
2470 2444 :on "hide"
2471 (defun widget-help-action (widget &optional event) 2445 :off "show"
2472 "Toggle documentation for WIDGET." 2446 :value-create 'widget-visibility-value-create
2473 (let ((old (widget-get widget :doc)) 2447 :action 'widget-toggle-action
2474 (new (widget-get widget :widget-doc))) 2448 :match (lambda (widget value) t))
2475 (widget-put widget :doc new) 2449
2476 (widget-put widget :widget-doc old)) 2450 (defun widget-visibility-value-create (widget)
2451 ;; Insert text representing the `on' and `off' states.
2452 (let ((on (widget-get widget :on))
2453 (off (widget-get widget :off)))
2454 (if on
2455 (setq on (concat widget-push-button-prefix
2456 on
2457 widget-push-button-suffix))
2458 (setq on ""))
2459 (if off
2460 (setq off (concat widget-push-button-prefix
2461 off
2462 widget-push-button-suffix))
2463 (setq off ""))
2464 (if (widget-value widget)
2465 (widget-glyph-insert widget on "down" "down-pushed")
2466 (widget-glyph-insert widget off "right" "right-pushed")
2467 (insert "..."))))
2468
2469 ;;; The `documentation-string' Widget.
2470
2471 (defface widget-documentation-face '((((class color)
2472 (background dark))
2473 (:foreground "lime green"))
2474 (((class color)
2475 (background light))
2476 (:foreground "dark green"))
2477 (t nil))
2478 "Face used for documentation text."
2479 :group 'widgets)
2480
2481 (define-widget 'documentation-string 'item
2482 "A documentation string."
2483 :format "%v"
2484 :action 'widget-documentation-string-action
2485 :value-delete 'widget-children-value-delete
2486 :value-create 'widget-documentation-string-value-create)
2487
2488 (defun widget-documentation-string-value-create (widget)
2489 ;; Insert documentation string.
2490 (let ((doc (widget-value widget))
2491 (shown (widget-get (widget-get widget :parent) :documentation-shown)))
2492 (if (string-match "\n" doc)
2493 (let ((before (substring doc 0 (match-beginning 0)))
2494 (after (substring doc (match-beginning 0)))
2495 (start (point))
2496 buttons)
2497 (insert before " ")
2498 (widget-specify-doc widget start (point))
2499 (push (widget-create-child-and-convert
2500 widget 'visibility
2501 :off nil
2502 :action 'widget-parent-action
2503 shown)
2504 buttons)
2505 (when shown
2506 (setq start (point))
2507 (insert after)
2508 (widget-specify-doc widget start (point)))
2509 (widget-put widget :buttons buttons))
2510 (insert doc)))
2511 (insert "\n"))
2512
2513 (defun widget-documentation-string-action (widget &rest ignore)
2514 ;; Toggle documentation.
2515 (let ((parent (widget-get widget :parent)))
2516 (widget-put parent :documentation-shown
2517 (not (widget-get parent :documentation-shown))))
2518 ;; Redraw.
2477 (widget-value-set widget (widget-value widget))) 2519 (widget-value-set widget (widget-value widget)))
2478 2520
2479 ;;; The Sexp Widgets. 2521 ;;; The Sexp Widgets.
2480 2522
2481 (define-widget 'const 'item 2523 (define-widget 'const 'item
2505 2547
2506 (define-widget 'string 'editable-field 2548 (define-widget 'string 'editable-field
2507 "A string" 2549 "A string"
2508 :tag "String" 2550 :tag "String"
2509 :format "%{%t%}: %v" 2551 :format "%{%t%}: %v"
2552 :complete-function 'ispell-complete-word
2510 :prompt-history 'widget-string-prompt-value-history) 2553 :prompt-history 'widget-string-prompt-value-history)
2511 2554
2512 (define-widget 'regexp 'string 2555 (define-widget 'regexp 'string
2513 "A regular expression." 2556 "A regular expression."
2514 :match 'widget-regexp-match 2557 :match 'widget-regexp-match
2532 (error (widget-put widget :error (error-message-string data)) 2575 (error (widget-put widget :error (error-message-string data))
2533 widget)))) 2576 widget))))
2534 2577
2535 (define-widget 'file 'string 2578 (define-widget 'file 'string
2536 "A file widget. 2579 "A file widget.
2537 It will read a file name from the minibuffer when activated." 2580 It will read a file name from the minibuffer when invoked."
2538 :prompt-value 'widget-file-prompt-value 2581 :prompt-value 'widget-file-prompt-value
2539 :format "%{%t%}: %v" 2582 :format "%{%t%}: %v"
2540 :tag "File" 2583 :tag "File"
2541 :action 'widget-file-action) 2584 :action 'widget-file-action)
2542 2585
2559 (menu-tag (widget-apply widget :menu-tag-get)) 2602 (menu-tag (widget-apply widget :menu-tag-get))
2560 (must-match (widget-get widget :must-match)) 2603 (must-match (widget-get widget :must-match))
2561 (answer (read-file-name (concat menu-tag ": (default `" value "') ") 2604 (answer (read-file-name (concat menu-tag ": (default `" value "') ")
2562 dir nil must-match file))) 2605 dir nil must-match file)))
2563 (widget-value-set widget (abbreviate-file-name answer)) 2606 (widget-value-set widget (abbreviate-file-name answer))
2564 (widget-apply widget :notify widget event) 2607 (widget-setup)
2565 (widget-setup))) 2608 (widget-apply widget :notify widget event)))
2566 2609
2567 (define-widget 'directory 'file 2610 (define-widget 'directory 'file
2568 "A directory widget. 2611 "A directory widget.
2569 It will read a directory name from the minibuffer when activated." 2612 It will read a directory name from the minibuffer when invoked."
2570 :tag "Directory") 2613 :tag "Directory")
2571 2614
2572 (defvar widget-symbol-prompt-value-history nil 2615 (defvar widget-symbol-prompt-value-history nil
2573 "History of input to `widget-symbol-prompt-value'.") 2616 "History of input to `widget-symbol-prompt-value'.")
2574 2617
2603 (defvar widget-function-prompt-value-history nil 2646 (defvar widget-function-prompt-value-history nil
2604 "History of input to `widget-function-prompt-value'.") 2647 "History of input to `widget-function-prompt-value'.")
2605 2648
2606 (define-widget 'function 'sexp 2649 (define-widget 'function 'sexp
2607 "A lisp function." 2650 "A lisp function."
2651 :complete-function 'lisp-complete-symbol
2608 :prompt-value 'widget-field-prompt-value 2652 :prompt-value 'widget-field-prompt-value
2609 :prompt-internal 'widget-symbol-prompt-internal 2653 :prompt-internal 'widget-symbol-prompt-internal
2610 :prompt-match 'fboundp 2654 :prompt-match 'fboundp
2611 :prompt-history 'widget-function-prompt-value-history 2655 :prompt-history 'widget-function-prompt-value-history
2612 :action 'widget-field-action 2656 :action 'widget-field-action
2634 :prompt-history 'widget-sexp-prompt-value-history 2678 :prompt-history 'widget-sexp-prompt-value-history
2635 :prompt-value 'widget-sexp-prompt-value) 2679 :prompt-value 'widget-sexp-prompt-value)
2636 2680
2637 (defun widget-sexp-value-to-internal (widget value) 2681 (defun widget-sexp-value-to-internal (widget value)
2638 ;; Use pp for printer representation. 2682 ;; Use pp for printer representation.
2639 (let ((pp (pp-to-string value))) 2683 (let ((pp (if (symbolp value)
2684 (prin1-to-string value)
2685 (pp-to-string value))))
2640 (while (string-match "\n\\'" pp) 2686 (while (string-match "\n\\'" pp)
2641 (setq pp (substring pp 0 -1))) 2687 (setq pp (substring pp 0 -1)))
2642 (if (or (string-match "\n\\'" pp) 2688 (if (or (string-match "\n\\'" pp)
2643 (> (length pp) 40)) 2689 (> (length pp) 40))
2644 (concat "\n" pp) 2690 (concat "\n" pp)
2841 "A color name (with sample)." 2887 "A color name (with sample)."
2842 :format "%v (%{sample%})\n" 2888 :format "%v (%{sample%})\n"
2843 :sample-face-get 'widget-color-item-button-face-get) 2889 :sample-face-get 'widget-color-item-button-face-get)
2844 2890
2845 (defun widget-color-item-button-face-get (widget) 2891 (defun widget-color-item-button-face-get (widget)
2846 ;; We create a face from the value. 2892 (let ((symbol (intern (concat "fg:" (widget-value widget)))))
2847 (require 'facemenu) 2893 (if (string-match "XEmacs" emacs-version)
2848 (condition-case nil 2894 (prog1 symbol
2849 (facemenu-get-face (intern (concat "fg:" (widget-value widget)))) 2895 (or (find-face symbol)
2850 (error 'default))) 2896 (set-face-foreground (make-face symbol) (widget-value widget))))
2897 (condition-case nil
2898 (facemenu-get-face symbol)
2899 (error 'default)))))
2851 2900
2852 (define-widget 'color 'push-button 2901 (define-widget 'color 'push-button
2853 "Choose a color name (with sample)." 2902 "Choose a color name (with sample)."
2854 :format "%[%t%]: %v" 2903 :format "%[%t%]: %v"
2855 :tag "Color" 2904 :tag "Color"
2900 nil nil nil 'widget-color-history)) 2949 nil nil nil 'widget-color-history))
2901 (t 2950 (t
2902 (read-string prompt (widget-value widget)))))) 2951 (read-string prompt (widget-value widget))))))
2903 (unless (zerop (length answer)) 2952 (unless (zerop (length answer))
2904 (widget-value-set widget answer) 2953 (widget-value-set widget answer)
2905 (widget-apply widget :notify widget event) 2954 (widget-setup)
2906 (widget-setup)))) 2955 (widget-apply widget :notify widget event))))
2907 2956
2908 ;;; The Help Echo 2957 ;;; The Help Echo
2909 2958
2910 (defun widget-echo-help-mouse () 2959 (defun widget-echo-help-mouse ()
2911 "Display the help message for the widget under the mouse. 2960 "Display the help message for the widget under the mouse.
2939 (remove-hook 'post-command-hook 'widget-stop-mouse-tracking) 2988 (remove-hook 'post-command-hook 'widget-stop-mouse-tracking)
2940 (setq track-mouse nil)) 2989 (setq track-mouse nil))
2941 2990
2942 (defun widget-at (pos) 2991 (defun widget-at (pos)
2943 "The button or field at POS." 2992 "The button or field at POS."
2944 (or (get-text-property pos 'button) 2993 (or (get-char-property pos 'button)
2945 (get-text-property pos 'field))) 2994 (get-char-property pos 'field)))
2946 2995
2947 (defun widget-echo-help (pos) 2996 (defun widget-echo-help (pos)
2948 "Display the help echo for widget at POS." 2997 "Display the help echo for widget at POS."
2949 (let* ((widget (widget-at pos)) 2998 (let* ((widget (widget-at pos))
2950 (help-echo (and widget (widget-get widget :help-echo)))) 2999 (help-echo (and widget (widget-get widget :help-echo))))