Mercurial > hg > xemacs-beta
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)))) |