diff options
| author | Per Abrahamsen | 1997-05-14 17:31:13 +0000 |
|---|---|---|
| committer | Per Abrahamsen | 1997-05-14 17:31:13 +0000 |
| commit | a3c88c59875e24341f55af4e0b40da96558c655e (patch) | |
| tree | 42d379391d4fbe6c7b3390640bfda6bc8cfc941d | |
| parent | 86bd10bcd8c1c2c189d8599287daa7d2bb3d4c70 (diff) | |
| download | emacs-a3c88c59875e24341f55af4e0b40da96558c655e.tar.gz emacs-a3c88c59875e24341f55af4e0b40da96558c655e.zip | |
Synched with 1.97.
| -rw-r--r-- | lisp/custom.el | 2 | ||||
| -rw-r--r-- | lisp/wid-browse.el | 19 | ||||
| -rw-r--r-- | lisp/wid-edit.el | 527 | ||||
| -rw-r--r-- | lisp/widget.el | 7 |
4 files changed, 385 insertions, 170 deletions
diff --git a/lisp/custom.el b/lisp/custom.el index d49265d0c12..aa03886ac67 100644 --- a/lisp/custom.el +++ b/lisp/custom.el | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | ;; | 4 | ;; |
| 5 | ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> | 5 | ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> |
| 6 | ;; Keywords: help, faces | 6 | ;; Keywords: help, faces |
| 7 | ;; Version: 1.90 | 7 | ;; Version: 1.97 |
| 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. |
diff --git a/lisp/wid-browse.el b/lisp/wid-browse.el index 984d802f75b..f8e309a1a3b 100644 --- a/lisp/wid-browse.el +++ b/lisp/wid-browse.el | |||
| @@ -4,9 +4,26 @@ | |||
| 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.90 | 7 | ;; Version: 1.97 |
| 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. | ||
| 11 | |||
| 12 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 13 | ;; it under the terms of the GNU General Public License as published by | ||
| 14 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 15 | ;; any later version. | ||
| 16 | |||
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | ;; GNU General Public License for more details. | ||
| 21 | |||
| 22 | ;; You should have received a copy of the GNU General Public License | ||
| 23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 24 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 25 | ;; Boston, MA 02111-1307, USA. | ||
| 26 | |||
| 10 | ;;; Commentary: | 27 | ;;; Commentary: |
| 11 | ;; | 28 | ;; |
| 12 | ;; Widget browser. See `widget.el'. | 29 | ;; Widget browser. See `widget.el'. |
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el index 555ab181f1a..9542df9089e 100644 --- a/lisp/wid-edit.el +++ b/lisp/wid-edit.el | |||
| @@ -4,7 +4,7 @@ | |||
| 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.90 | 7 | ;; Version: 1.97 |
| 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. |
| @@ -65,6 +65,16 @@ and `end-open' if it should sticky to the front." | |||
| 65 | "Make text between FROM and TO intangible." | 65 | "Make text between FROM and TO intangible." |
| 66 | (put-text-property from to 'intangible 'front))) | 66 | (put-text-property from to 'intangible 'front))) |
| 67 | 67 | ||
| 68 | (if (string-match "XEmacs" emacs-version) | ||
| 69 | (defun widget-event-point (event) | ||
| 70 | "Character position of the end of event if that exists, or nil." | ||
| 71 | (if (mouse-event-p event) | ||
| 72 | (event-point event) | ||
| 73 | nil)) | ||
| 74 | (defun widget-event-point (event) | ||
| 75 | "Character position of the end of event if that exists, or nil." | ||
| 76 | (posn-point (event-end event)))) | ||
| 77 | |||
| 68 | ;; The following should go away when bundled with Emacs. | 78 | ;; The following should go away when bundled with Emacs. |
| 69 | (condition-case () | 79 | (condition-case () |
| 70 | (require 'custom) | 80 | (require 'custom) |
| @@ -82,14 +92,14 @@ and `end-open' if it should sticky to the front." | |||
| 82 | (copy-face 'bold 'widget-button-face) | 92 | (copy-face 'bold 'widget-button-face) |
| 83 | (copy-face 'italic 'widget-field-face))) | 93 | (copy-face 'italic 'widget-field-face))) |
| 84 | 94 | ||
| 85 | (unless (fboundp 'event-point) | 95 | (unless (fboundp 'button-release-event-p) |
| 86 | ;; XEmacs function missing in Emacs. | 96 | ;; XEmacs function missing from Emacs. |
| 87 | (defun event-point (event) | 97 | (defun button-release-event-p (event) |
| 88 | "Return the character position of the given mouse-motion, button-press, | 98 | "Non-nil if EVENT is a mouse-button-release event object." |
| 89 | or button-release event. If the event did not occur over a window, or did | 99 | (and (eventp event) |
| 90 | not occur over text, then this returns nil. Otherwise, it returns an index | 100 | (memq (event-basic-type event) '(mouse-1 mouse-2 mouse-3)) |
| 91 | into the buffer visible in the event's window." | 101 | (or (memq 'click (event-modifiers event)) |
| 92 | (posn-point (event-start event)))) | 102 | (memq 'drag (event-modifiers event)))))) |
| 93 | 103 | ||
| 94 | (unless (fboundp 'error-message-string) | 104 | (unless (fboundp 'error-message-string) |
| 95 | ;; Emacs function missing in XEmacs. | 105 | ;; Emacs function missing in XEmacs. |
| @@ -142,12 +152,6 @@ into the buffer visible in the event's window." | |||
| 142 | "Face used for editable fields." | 152 | "Face used for editable fields." |
| 143 | :group 'widgets) | 153 | :group 'widgets) |
| 144 | 154 | ||
| 145 | (defcustom widget-menu-max-size 40 | ||
| 146 | "Largest number of items allowed in a popup-menu. | ||
| 147 | Larger menus are read through the minibuffer." | ||
| 148 | :group 'widgets | ||
| 149 | :type 'integer) | ||
| 150 | |||
| 151 | ;;; Utility functions. | 155 | ;;; Utility functions. |
| 152 | ;; | 156 | ;; |
| 153 | ;; These are not really widget specific. | 157 | ;; These are not really widget specific. |
| @@ -179,6 +183,12 @@ Larger menus are read through the minibuffer." | |||
| 179 | (buffer-disable-undo (current-buffer)) | 183 | (buffer-disable-undo (current-buffer)) |
| 180 | (buffer-enable-undo)) | 184 | (buffer-enable-undo)) |
| 181 | 185 | ||
| 186 | (defcustom widget-menu-max-size 40 | ||
| 187 | "Largest number of items allowed in a popup-menu. | ||
| 188 | Larger menus are read through the minibuffer." | ||
| 189 | :group 'widgets | ||
| 190 | :type 'integer) | ||
| 191 | |||
| 182 | (defun widget-choose (title items &optional event) | 192 | (defun widget-choose (title items &optional event) |
| 183 | "Choose an item from a list. | 193 | "Choose an item from a list. |
| 184 | 194 | ||
| @@ -225,36 +235,6 @@ minibuffer." | |||
| 225 | (cdr (assoc val items))) | 235 | (cdr (assoc val items))) |
| 226 | nil))))) | 236 | nil))))) |
| 227 | 237 | ||
| 228 | (defun widget-get-sibling (widget) | ||
| 229 | "Get the item WIDGET is assumed to toggle. | ||
| 230 | This is only meaningful for radio buttons or checkboxes in a list." | ||
| 231 | (let* ((parent (widget-get widget :parent)) | ||
| 232 | (children (widget-get parent :children)) | ||
| 233 | child) | ||
| 234 | (catch 'child | ||
| 235 | (while children | ||
| 236 | (setq child (car children) | ||
| 237 | children (cdr children)) | ||
| 238 | (when (eq (widget-get child :button) widget) | ||
| 239 | (throw 'child child))) | ||
| 240 | nil))) | ||
| 241 | |||
| 242 | ;;; Helper functions. | ||
| 243 | ;; | ||
| 244 | ;; These are widget specific. | ||
| 245 | |||
| 246 | ;;;###autoload | ||
| 247 | (defun widget-prompt-value (widget prompt &optional value unbound) | ||
| 248 | "Prompt for a value matching WIDGET, using PROMPT. | ||
| 249 | The current value is assumed to be VALUE, unless UNBOUND is non-nil." | ||
| 250 | (unless (listp widget) | ||
| 251 | (setq widget (list widget))) | ||
| 252 | (setq widget (widget-convert widget)) | ||
| 253 | (let ((answer (widget-apply widget :prompt-value prompt value unbound))) | ||
| 254 | (unless (widget-apply widget :match answer) | ||
| 255 | (error "Value does not match %S type." (car widget))) | ||
| 256 | answer)) | ||
| 257 | |||
| 258 | ;;; Widget text specifications. | 238 | ;;; Widget text specifications. |
| 259 | ;; | 239 | ;; |
| 260 | ;; These functions are for specifying text properties. | 240 | ;; These functions are for specifying text properties. |
| @@ -526,6 +506,37 @@ ARGS are passed as extra arguments to the function." | |||
| 526 | (widget-apply widget :action event) | 506 | (widget-apply widget :action event) |
| 527 | (error "Attempt to perform action on inactive widget"))) | 507 | (error "Attempt to perform action on inactive widget"))) |
| 528 | 508 | ||
| 509 | ;;; Helper functions. | ||
| 510 | ;; | ||
| 511 | ;; These are widget specific. | ||
| 512 | |||
| 513 | ;;;###autoload | ||
| 514 | (defun widget-prompt-value (widget prompt &optional value unbound) | ||
| 515 | "Prompt for a value matching WIDGET, using PROMPT. | ||
| 516 | The current value is assumed to be VALUE, unless UNBOUND is non-nil." | ||
| 517 | (unless (listp widget) | ||
| 518 | (setq widget (list widget))) | ||
| 519 | (setq prompt (format "[%s] %s" (widget-type widget) prompt)) | ||
| 520 | (setq widget (widget-convert widget)) | ||
| 521 | (let ((answer (widget-apply widget :prompt-value prompt value unbound))) | ||
| 522 | (unless (widget-apply widget :match answer) | ||
| 523 | (error "Value does not match %S type." (car widget))) | ||
| 524 | answer)) | ||
| 525 | |||
| 526 | (defun widget-get-sibling (widget) | ||
| 527 | "Get the item WIDGET is assumed to toggle. | ||
| 528 | This is only meaningful for radio buttons or checkboxes in a list." | ||
| 529 | (let* ((parent (widget-get widget :parent)) | ||
| 530 | (children (widget-get parent :children)) | ||
| 531 | child) | ||
| 532 | (catch 'child | ||
| 533 | (while children | ||
| 534 | (setq child (car children) | ||
| 535 | children (cdr children)) | ||
| 536 | (when (eq (widget-get child :button) widget) | ||
| 537 | (throw 'child child))) | ||
| 538 | nil))) | ||
| 539 | |||
| 529 | ;;; Glyphs. | 540 | ;;; Glyphs. |
| 530 | 541 | ||
| 531 | (defcustom widget-glyph-directory (concat data-directory "custom/") | 542 | (defcustom widget-glyph-directory (concat data-directory "custom/") |
| @@ -572,14 +583,23 @@ cause the last created widget to be activated." | |||
| 572 | ;; File not readable, give up. | 583 | ;; File not readable, give up. |
| 573 | (insert tag)))))) | 584 | (insert tag)))))) |
| 574 | 585 | ||
| 575 | (defun widget-glyph-insert-glyph (widget tag glyph) | 586 | (defun widget-glyph-insert-glyph (widget tag glyph &optional down inactive) |
| 576 | "In WIDGET, with alternative text TAG, insert GLYPH." | 587 | "In WIDGET, with alternative text TAG, insert GLYPH." |
| 577 | (set-glyph-image glyph (cons 'tty tag)) | 588 | (set-glyph-image glyph (cons 'tty tag)) |
| 578 | (set-glyph-property glyph 'widget widget) | 589 | (set-glyph-property glyph 'widget widget) |
| 590 | (when down | ||
| 591 | (set-glyph-image down (cons 'tty tag)) | ||
| 592 | (set-glyph-property down 'widget widget)) | ||
| 593 | (when inactive | ||
| 594 | (set-glyph-image inactive (cons 'tty tag)) | ||
| 595 | (set-glyph-property inactive 'widget widget)) | ||
| 579 | (insert "*") | 596 | (insert "*") |
| 580 | (add-text-properties (1- (point)) (point) | 597 | (add-text-properties (1- (point)) (point) |
| 581 | (list 'invisible t | 598 | (list 'invisible t |
| 582 | 'end-glyph glyph)) | 599 | 'end-glyph glyph)) |
| 600 | (widget-put widget :glyph-up glyph) | ||
| 601 | (when down (widget-put widget :glyph-down down)) | ||
| 602 | (when inactive (widget-put widget :glyph-inactive inactive)) | ||
| 583 | (let ((help-echo (widget-get widget :help-echo))) | 603 | (let ((help-echo (widget-get widget :help-echo))) |
| 584 | (when help-echo | 604 | (when help-echo |
| 585 | (let ((extent (extent-at (1- (point)) nil 'end-glyph)) | 605 | (let ((extent (extent-at (1- (point)) nil 'end-glyph)) |
| @@ -706,11 +726,11 @@ Recommended as a parent keymap for modes using widgets.") | |||
| 706 | (define-key widget-keymap "\M-\t" 'widget-backward) | 726 | (define-key widget-keymap "\M-\t" 'widget-backward) |
| 707 | (define-key widget-keymap [(shift tab)] 'widget-backward) | 727 | (define-key widget-keymap [(shift tab)] 'widget-backward) |
| 708 | (define-key widget-keymap [backtab] 'widget-backward) | 728 | (define-key widget-keymap [backtab] 'widget-backward) |
| 709 | (if (string-match "XEmacs" (emacs-version)) | 729 | (if (string-match "XEmacs" emacs-version) |
| 710 | (progn | 730 | (progn |
| 711 | (define-key widget-keymap [button2] 'widget-button-click) | 731 | ;;Glyph support. |
| 712 | (define-key widget-keymap [button1] 'widget-button1-click)) | 732 | (define-key widget-keymap [button1] 'widget-button1-click) |
| 713 | (define-key widget-keymap [mouse-2] 'ignore) | 733 | (define-key widget-keymap [button2] 'widget-button-click)) |
| 714 | (define-key widget-keymap [down-mouse-2] 'widget-button-click)) | 734 | (define-key widget-keymap [down-mouse-2] 'widget-button-click)) |
| 715 | (define-key widget-keymap "\C-m" 'widget-button-press)) | 735 | (define-key widget-keymap "\C-m" 'widget-button-press)) |
| 716 | 736 | ||
| @@ -750,19 +770,56 @@ Recommended as a parent keymap for modes using widgets.") | |||
| 750 | (call-interactively | 770 | (call-interactively |
| 751 | (lookup-key widget-global-map (this-command-keys)))))) | 771 | (lookup-key widget-global-map (this-command-keys)))))) |
| 752 | 772 | ||
| 773 | (defface widget-button-pressed-face | ||
| 774 | '((((class color)) | ||
| 775 | (:foreground "red")) | ||
| 776 | (t | ||
| 777 | (:bold t :underline t))) | ||
| 778 | "Face used for pressed buttons." | ||
| 779 | :group 'widgets) | ||
| 780 | |||
| 753 | (defun widget-button-click (event) | 781 | (defun widget-button-click (event) |
| 754 | "Activate button below mouse pointer." | 782 | "Activate button below mouse pointer." |
| 755 | (interactive "@e") | 783 | (interactive "@e") |
| 756 | (cond ((and (fboundp 'event-glyph) | 784 | (cond ((and (fboundp 'event-glyph) |
| 757 | (event-glyph event)) | 785 | (event-glyph event)) |
| 758 | (let ((widget (glyph-property (event-glyph event) 'widget))) | 786 | (widget-glyph-click event)) |
| 759 | (if widget | 787 | ((widget-event-point event) |
| 760 | (widget-apply-action widget event) | 788 | (let* ((pos (widget-event-point event)) |
| 761 | (message "You clicked on a glyph.")))) | 789 | (button (get-text-property pos 'button))) |
| 762 | ((event-point event) | ||
| 763 | (let ((button (get-text-property (event-point event) 'button))) | ||
| 764 | (if button | 790 | (if button |
| 765 | (widget-apply-action button event) | 791 | (let ((begin (previous-single-property-change (1+ pos) 'button)) |
| 792 | (end (next-single-property-change pos 'button)) | ||
| 793 | overlay) | ||
| 794 | (unwind-protect | ||
| 795 | (let ((track-mouse t)) | ||
| 796 | (setq overlay (make-overlay begin end)) | ||
| 797 | (overlay-put overlay 'face 'widget-button-pressed-face) | ||
| 798 | (overlay-put overlay | ||
| 799 | 'mouse-face 'widget-button-pressed-face) | ||
| 800 | (unless (widget-apply button :mouse-down-action event) | ||
| 801 | (while (not (button-release-event-p event)) | ||
| 802 | (setq event (if (fboundp 'read-event) | ||
| 803 | (read-event) | ||
| 804 | (next-event)) | ||
| 805 | pos (widget-event-point event)) | ||
| 806 | (if (and pos | ||
| 807 | (eq (get-text-property pos 'button) | ||
| 808 | button)) | ||
| 809 | (progn | ||
| 810 | (overlay-put overlay | ||
| 811 | 'face | ||
| 812 | 'widget-button-pressed-face) | ||
| 813 | (overlay-put overlay | ||
| 814 | 'mouse-face | ||
| 815 | 'widget-button-pressed-face)) | ||
| 816 | (overlay-put overlay 'face nil) | ||
| 817 | (overlay-put overlay 'mouse-face nil)))) | ||
| 818 | |||
| 819 | (when (and pos | ||
| 820 | (eq (get-text-property pos 'button) button)) | ||
| 821 | (widget-apply-action button event))) | ||
| 822 | (delete-overlay overlay))) | ||
| 766 | (call-interactively | 823 | (call-interactively |
| 767 | (or (lookup-key widget-global-map [ button2 ]) | 824 | (or (lookup-key widget-global-map [ button2 ]) |
| 768 | (lookup-key widget-global-map [ down-mouse-2 ]) | 825 | (lookup-key widget-global-map [ down-mouse-2 ]) |
| @@ -775,12 +832,36 @@ Recommended as a parent keymap for modes using widgets.") | |||
| 775 | (interactive "@e") | 832 | (interactive "@e") |
| 776 | (if (and (fboundp 'event-glyph) | 833 | (if (and (fboundp 'event-glyph) |
| 777 | (event-glyph event)) | 834 | (event-glyph event)) |
| 778 | (let ((widget (glyph-property (event-glyph event) 'widget))) | 835 | (widget-glyph-click event) |
| 779 | (if widget | ||
| 780 | (widget-apply-action widget event) | ||
| 781 | (message "You clicked on a glyph."))) | ||
| 782 | (call-interactively (lookup-key widget-global-map (this-command-keys))))) | 836 | (call-interactively (lookup-key widget-global-map (this-command-keys))))) |
| 783 | 837 | ||
| 838 | (defun widget-glyph-click (event) | ||
| 839 | "Handle click on a glyph." | ||
| 840 | (let* ((glyph (event-glyph event)) | ||
| 841 | (widget (glyph-property glyph 'widget)) | ||
| 842 | (extent (event-glyph-extent event)) | ||
| 843 | (down-glyph (or (and widget (widget-get widget :glyph-down)) glyph)) | ||
| 844 | (up-glyph (or (and widget (widget-get widget :glyph-up)) glyph)) | ||
| 845 | (last event)) | ||
| 846 | ;; Wait for the release. | ||
| 847 | (while (not (button-release-event-p last)) | ||
| 848 | (if (eq extent (event-glyph-extent last)) | ||
| 849 | (set-extent-property extent 'end-glyph down-glyph) | ||
| 850 | (set-extent-property extent 'end-glyph up-glyph)) | ||
| 851 | (setq last (next-event event))) | ||
| 852 | ;; Release glyph. | ||
| 853 | (when down-glyph | ||
| 854 | (set-extent-property extent 'end-glyph up-glyph)) | ||
| 855 | ;; Apply widget action. | ||
| 856 | (when (eq extent (event-glyph-extent last)) | ||
| 857 | (let ((widget (glyph-property (event-glyph event) 'widget))) | ||
| 858 | (cond ((null widget) | ||
| 859 | (message "You clicked on a glyph.")) | ||
| 860 | ((not (widget-apply widget :active)) | ||
| 861 | (message "This glyph is inactive.")) | ||
| 862 | (t | ||
| 863 | (widget-apply-action widget event))))))) | ||
| 864 | |||
| 784 | (defun widget-button-press (pos &optional event) | 865 | (defun widget-button-press (pos &optional event) |
| 785 | "Activate button at POS." | 866 | "Activate button at POS." |
| 786 | (interactive "@d") | 867 | (interactive "@d") |
| @@ -1007,6 +1088,11 @@ With optional ARG, move across that many fields." | |||
| 1007 | ;; | 1088 | ;; |
| 1008 | ;; These functions are used in the definition of multiple widgets. | 1089 | ;; These functions are used in the definition of multiple widgets. |
| 1009 | 1090 | ||
| 1091 | (defun widget-parent-action (widget &optional event) | ||
| 1092 | "Tell :parent of WIDGET to handle the :action. | ||
| 1093 | Optional EVENT is the event that triggered the action." | ||
| 1094 | (widget-apply (widget-get widget :parent) :action event)) | ||
| 1095 | |||
| 1010 | (defun widget-children-value-delete (widget) | 1096 | (defun widget-children-value-delete (widget) |
| 1011 | "Delete all :children and :buttons in WIDGET." | 1097 | "Delete all :children and :buttons in WIDGET." |
| 1012 | (mapcar 'widget-delete (widget-get widget :children)) | 1098 | (mapcar 'widget-delete (widget-get widget :children)) |
| @@ -1014,11 +1100,36 @@ With optional ARG, move across that many fields." | |||
| 1014 | (mapcar 'widget-delete (widget-get widget :buttons)) | 1100 | (mapcar 'widget-delete (widget-get widget :buttons)) |
| 1015 | (widget-put widget :buttons nil)) | 1101 | (widget-put widget :buttons nil)) |
| 1016 | 1102 | ||
| 1103 | (defun widget-children-validate (widget) | ||
| 1104 | "All the :children must be valid." | ||
| 1105 | (let ((children (widget-get widget :children)) | ||
| 1106 | child found) | ||
| 1107 | (while (and children (not found)) | ||
| 1108 | (setq child (car children) | ||
| 1109 | children (cdr children) | ||
| 1110 | found (widget-apply child :validate))) | ||
| 1111 | found)) | ||
| 1112 | |||
| 1017 | (defun widget-types-convert-widget (widget) | 1113 | (defun widget-types-convert-widget (widget) |
| 1018 | "Convert :args as widget types in WIDGET." | 1114 | "Convert :args as widget types in WIDGET." |
| 1019 | (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args))) | 1115 | (widget-put widget :args (mapcar 'widget-convert (widget-get widget :args))) |
| 1020 | widget) | 1116 | widget) |
| 1021 | 1117 | ||
| 1118 | (defun widget-value-convert-widget (widget) | ||
| 1119 | "Initialize :value from :args in WIDGET." | ||
| 1120 | (let ((args (widget-get widget :args))) | ||
| 1121 | (when args | ||
| 1122 | (widget-put widget :value (car args)) | ||
| 1123 | ;; Don't convert :value here, as this is done in `widget-convert'. | ||
| 1124 | ;; (widget-put widget :value (widget-apply widget | ||
| 1125 | ;; :value-to-internal (car args))) | ||
| 1126 | (widget-put widget :args nil))) | ||
| 1127 | widget) | ||
| 1128 | |||
| 1129 | (defun widget-value-value-get (widget) | ||
| 1130 | "Return the :value property of WIDGET." | ||
| 1131 | (widget-get widget :value)) | ||
| 1132 | |||
| 1022 | ;;; The `default' Widget. | 1133 | ;;; The `default' Widget. |
| 1023 | 1134 | ||
| 1024 | (define-widget 'default nil | 1135 | (define-widget 'default nil |
| @@ -1039,6 +1150,7 @@ With optional ARG, move across that many fields." | |||
| 1039 | :active 'widget-default-active | 1150 | :active 'widget-default-active |
| 1040 | :activate 'widget-specify-active | 1151 | :activate 'widget-specify-active |
| 1041 | :deactivate 'widget-default-deactivate | 1152 | :deactivate 'widget-default-deactivate |
| 1153 | :mouse-down-action (lambda (widget event) nil) | ||
| 1042 | :action 'widget-default-action | 1154 | :action 'widget-default-action |
| 1043 | :notify 'widget-default-notify | 1155 | :notify 'widget-default-notify |
| 1044 | :prompt-value 'widget-default-prompt-value) | 1156 | :prompt-value 'widget-default-prompt-value) |
| @@ -1233,24 +1345,15 @@ With optional ARG, move across that many fields." | |||
| 1233 | 1345 | ||
| 1234 | (define-widget 'item 'default | 1346 | (define-widget 'item 'default |
| 1235 | "Constant items for inclusion in other widgets." | 1347 | "Constant items for inclusion in other widgets." |
| 1236 | :convert-widget 'widget-item-convert-widget | 1348 | :convert-widget 'widget-value-convert-widget |
| 1237 | :value-create 'widget-item-value-create | 1349 | :value-create 'widget-item-value-create |
| 1238 | :value-delete 'ignore | 1350 | :value-delete 'ignore |
| 1239 | :value-get 'widget-item-value-get | 1351 | :value-get 'widget-value-value-get |
| 1240 | :match 'widget-item-match | 1352 | :match 'widget-item-match |
| 1241 | :match-inline 'widget-item-match-inline | 1353 | :match-inline 'widget-item-match-inline |
| 1242 | :action 'widget-item-action | 1354 | :action 'widget-item-action |
| 1243 | :format "%t\n") | 1355 | :format "%t\n") |
| 1244 | 1356 | ||
| 1245 | (defun widget-item-convert-widget (widget) | ||
| 1246 | ;; Initialize :value from :args in WIDGET. | ||
| 1247 | (let ((args (widget-get widget :args))) | ||
| 1248 | (when args | ||
| 1249 | (widget-put widget :value (widget-apply widget | ||
| 1250 | :value-to-internal (car args))) | ||
| 1251 | (widget-put widget :args nil))) | ||
| 1252 | widget) | ||
| 1253 | |||
| 1254 | (defun widget-item-value-create (widget) | 1357 | (defun widget-item-value-create (widget) |
| 1255 | ;; Insert the printed representation of the value. | 1358 | ;; Insert the printed representation of the value. |
| 1256 | (let ((standard-output (current-buffer))) | 1359 | (let ((standard-output (current-buffer))) |
| @@ -1273,10 +1376,6 @@ With optional ARG, move across that many fields." | |||
| 1273 | ;; Just notify itself. | 1376 | ;; Just notify itself. |
| 1274 | (widget-apply widget :notify widget event)) | 1377 | (widget-apply widget :notify widget event)) |
| 1275 | 1378 | ||
| 1276 | (defun widget-item-value-get (widget) | ||
| 1277 | ;; Items are simple. | ||
| 1278 | (widget-get widget :value)) | ||
| 1279 | |||
| 1280 | ;;; The `push-button' Widget. | 1379 | ;;; The `push-button' Widget. |
| 1281 | 1380 | ||
| 1282 | (defcustom widget-push-button-gui t | 1381 | (defcustom widget-push-button-gui t |
| @@ -1310,7 +1409,9 @@ With optional ARG, move across that many fields." | |||
| 1310 | (setq gui (make-gui-button tag 'widget-gui-action widget)) | 1409 | (setq gui (make-gui-button tag 'widget-gui-action widget)) |
| 1311 | (push (cons tag gui) widget-push-button-cache)) | 1410 | (push (cons tag gui) widget-push-button-cache)) |
| 1312 | (widget-glyph-insert-glyph widget text | 1411 | (widget-glyph-insert-glyph widget text |
| 1313 | (make-glyph (car (aref gui 1))))) | 1412 | (make-glyph (nth 0 (aref gui 1))) |
| 1413 | (make-glyph (nth 1 (aref gui 1))) | ||
| 1414 | (make-glyph (nth 2 (aref gui 1))))) | ||
| 1314 | (insert text)))) | 1415 | (insert text)))) |
| 1315 | 1416 | ||
| 1316 | (defun widget-gui-action (widget) | 1417 | (defun widget-gui-action (widget) |
| @@ -1332,17 +1433,7 @@ With optional ARG, move across that many fields." | |||
| 1332 | 1433 | ||
| 1333 | (defun widget-info-link-action (widget &optional event) | 1434 | (defun widget-info-link-action (widget &optional event) |
| 1334 | "Open the info node specified by WIDGET." | 1435 | "Open the info node specified by WIDGET." |
| 1335 | (Info-goto-node (widget-value widget)) | 1436 | (Info-goto-node (widget-value widget))) |
| 1336 | ;; Steal button release event. | ||
| 1337 | (if (and (fboundp 'button-press-event-p) | ||
| 1338 | (fboundp 'next-command-event)) | ||
| 1339 | ;; XEmacs | ||
| 1340 | (and event | ||
| 1341 | (button-press-event-p event) | ||
| 1342 | (next-command-event)) | ||
| 1343 | ;; Emacs | ||
| 1344 | (when (memq 'down (event-modifiers event)) | ||
| 1345 | (read-event)))) | ||
| 1346 | 1437 | ||
| 1347 | ;;; The `url-link' Widget. | 1438 | ;;; The `url-link' Widget. |
| 1348 | 1439 | ||
| @@ -1359,10 +1450,13 @@ With optional ARG, move across that many fields." | |||
| 1359 | 1450 | ||
| 1360 | (define-widget 'editable-field 'default | 1451 | (define-widget 'editable-field 'default |
| 1361 | "An editable text field." | 1452 | "An editable text field." |
| 1362 | :convert-widget 'widget-item-convert-widget | 1453 | :convert-widget 'widget-value-convert-widget |
| 1363 | :keymap widget-field-keymap | 1454 | :keymap widget-field-keymap |
| 1364 | :format "%v" | 1455 | :format "%v" |
| 1365 | :value "" | 1456 | :value "" |
| 1457 | :prompt-internal 'widget-field-prompt-internal | ||
| 1458 | :prompt-history 'widget-field-history | ||
| 1459 | :prompt-value 'widget-field-prompt-value | ||
| 1366 | :action 'widget-field-action | 1460 | :action 'widget-field-action |
| 1367 | :validate 'widget-field-validate | 1461 | :validate 'widget-field-validate |
| 1368 | :valid-regexp "" | 1462 | :valid-regexp "" |
| @@ -1372,24 +1466,34 @@ With optional ARG, move across that many fields." | |||
| 1372 | :value-get 'widget-field-value-get | 1466 | :value-get 'widget-field-value-get |
| 1373 | :match 'widget-field-match) | 1467 | :match 'widget-field-match) |
| 1374 | 1468 | ||
| 1375 | ;; History of field minibuffer edits. | 1469 | (defvar widget-field-history nil |
| 1376 | (defvar widget-field-history nil) | 1470 | "History of field minibuffer edits.") |
| 1471 | |||
| 1472 | (defun widget-field-prompt-internal (widget prompt initial history) | ||
| 1473 | ;; Read string for WIDGET promptinhg with PROMPT. | ||
| 1474 | ;; INITIAL is the initial input and HISTORY is a symbol containing | ||
| 1475 | ;; the earlier input. | ||
| 1476 | (read-string prompt initial history)) | ||
| 1477 | |||
| 1478 | (defun widget-field-prompt-value (widget prompt value unbound) | ||
| 1479 | ;; Prompt for a string. | ||
| 1480 | (let ((initial (if unbound | ||
| 1481 | nil | ||
| 1482 | (cons (widget-apply widget :value-to-internal | ||
| 1483 | value) 0))) | ||
| 1484 | (history (widget-get widget :prompt-history))) | ||
| 1485 | (let ((answer (widget-apply widget | ||
| 1486 | :prompt-internal prompt initial history))) | ||
| 1487 | (widget-apply widget :value-to-external answer)))) | ||
| 1377 | 1488 | ||
| 1378 | (defun widget-field-action (widget &optional event) | 1489 | (defun widget-field-action (widget &optional event) |
| 1379 | ;; Edit the value in the minibuffer. | 1490 | ;; Edit the value in the minibuffer. |
| 1380 | (let ((tag (widget-apply widget :menu-tag-get)) | 1491 | (let ((invalid (widget-apply widget :validate))) |
| 1381 | (invalid (widget-apply widget :validate))) | 1492 | (let ((prompt (concat (widget-apply widget :menu-tag-get) ": ")) |
| 1382 | (when invalid | 1493 | (value (unless invalid |
| 1383 | (error (widget-get invalid :error))) | 1494 | (widget-value widget)))) |
| 1384 | (widget-value-set widget | 1495 | (let ((answer (widget-apply widget :prompt-value prompt value invalid) )) |
| 1385 | (widget-apply widget | 1496 | (widget-value-set widget answer))) |
| 1386 | :value-to-external | ||
| 1387 | (read-string (concat tag ": ") | ||
| 1388 | (widget-apply | ||
| 1389 | widget | ||
| 1390 | :value-to-internal | ||
| 1391 | (widget-value widget)) | ||
| 1392 | 'widget-field-history))) | ||
| 1393 | (widget-apply widget :notify widget event) | 1497 | (widget-apply widget :notify widget event) |
| 1394 | (widget-setup))) | 1498 | (widget-setup))) |
| 1395 | 1499 | ||
| @@ -1449,6 +1553,9 @@ With optional ARG, move across that many fields." | |||
| 1449 | (eq (char-after (1- to)) ?\ )) | 1553 | (eq (char-after (1- to)) ?\ )) |
| 1450 | (setq to (1- to))) | 1554 | (setq to (1- to))) |
| 1451 | (let ((result (buffer-substring-no-properties from to))) | 1555 | (let ((result (buffer-substring-no-properties from to))) |
| 1556 | (when (string-match "XEmacs" emacs-version) | ||
| 1557 | ;; XEmacs 20.1 bug: b-s-n-p doesn't clear all properties. | ||
| 1558 | (setq result (format "%s" result))) | ||
| 1452 | (when secret | 1559 | (when secret |
| 1453 | (let ((index 0)) | 1560 | (let ((index 0)) |
| 1454 | (while (< (+ from index) to) | 1561 | (while (< (+ from index) to) |
| @@ -1482,6 +1589,7 @@ With optional ARG, move across that many fields." | |||
| 1482 | :value-delete 'widget-children-value-delete | 1589 | :value-delete 'widget-children-value-delete |
| 1483 | :value-get 'widget-choice-value-get | 1590 | :value-get 'widget-choice-value-get |
| 1484 | :value-inline 'widget-choice-value-inline | 1591 | :value-inline 'widget-choice-value-inline |
| 1592 | :mouse-down-action 'widget-choice-mouse-down-action | ||
| 1485 | :action 'widget-choice-action | 1593 | :action 'widget-choice-action |
| 1486 | :error "Make a choice" | 1594 | :error "Make a choice" |
| 1487 | :validate 'widget-choice-validate | 1595 | :validate 'widget-choice-validate |
| @@ -1516,6 +1624,39 @@ With optional ARG, move across that many fields." | |||
| 1516 | ;; Get value of the child widget. | 1624 | ;; Get value of the child widget. |
| 1517 | (widget-apply (car (widget-get widget :children)) :value-inline)) | 1625 | (widget-apply (car (widget-get widget :children)) :value-inline)) |
| 1518 | 1626 | ||
| 1627 | (defcustom widget-choice-toggle nil | ||
| 1628 | "If non-nil, a binary choice will just toggle between the values. | ||
| 1629 | Otherwise, the user will explicitly have to choose between the values | ||
| 1630 | when he activate the menu." | ||
| 1631 | :type 'boolean | ||
| 1632 | :group 'widgets) | ||
| 1633 | |||
| 1634 | (defun widget-choice-mouse-down-action (widget &optional event) | ||
| 1635 | ;; Return non-nil if we need a menu. | ||
| 1636 | (let ((args (widget-get widget :args)) | ||
| 1637 | (old (widget-get widget :choice))) | ||
| 1638 | (cond ((not window-system) | ||
| 1639 | ;; No place to pop up a menu. | ||
| 1640 | nil) | ||
| 1641 | ((not (or (fboundp 'x-popup-menu) (fboundp 'popup-menu))) | ||
| 1642 | ;; No way to pop up a menu. | ||
| 1643 | nil) | ||
| 1644 | ((< (length args) 2) | ||
| 1645 | ;; Empty or singleton list, just return the value. | ||
| 1646 | nil) | ||
| 1647 | ((> (length args) widget-menu-max-size) | ||
| 1648 | ;; Too long, prompt. | ||
| 1649 | nil) | ||
| 1650 | ((> (length args) 2) | ||
| 1651 | ;; Reasonable sized list, use menu. | ||
| 1652 | t) | ||
| 1653 | ((and widget-choice-toggle (memq old args)) | ||
| 1654 | ;; We toggle. | ||
| 1655 | nil) | ||
| 1656 | (t | ||
| 1657 | ;; Ask which of the two. | ||
| 1658 | t)))) | ||
| 1659 | |||
| 1519 | (defun widget-choice-action (widget &optional event) | 1660 | (defun widget-choice-action (widget &optional event) |
| 1520 | ;; Make a choice. | 1661 | ;; Make a choice. |
| 1521 | (let ((args (widget-get widget :args)) | 1662 | (let ((args (widget-get widget :args)) |
| @@ -1534,7 +1675,8 @@ With optional ARG, move across that many fields." | |||
| 1534 | nil) | 1675 | nil) |
| 1535 | ((= (length args) 1) | 1676 | ((= (length args) 1) |
| 1536 | (nth 0 args)) | 1677 | (nth 0 args)) |
| 1537 | ((and (= (length args) 2) | 1678 | ((and widget-choice-toggle |
| 1679 | (= (length args) 2) | ||
| 1538 | (memq old args)) | 1680 | (memq old args)) |
| 1539 | (if (eq old (nth 0 args)) | 1681 | (if (eq old (nth 0 args)) |
| 1540 | (nth 1 args) | 1682 | (nth 1 args) |
| @@ -1789,13 +1931,9 @@ With optional ARG, move across that many fields." | |||
| 1789 | 1931 | ||
| 1790 | (define-widget 'choice-item 'item | 1932 | (define-widget 'choice-item 'item |
| 1791 | "Button items that delegate action events to their parents." | 1933 | "Button items that delegate action events to their parents." |
| 1792 | :action 'widget-choice-item-action | 1934 | :action 'widget-parent-action |
| 1793 | :format "%[%t%] \n") | 1935 | :format "%[%t%] \n") |
| 1794 | 1936 | ||
| 1795 | (defun widget-choice-item-action (widget &optional event) | ||
| 1796 | ;; Tell parent what happened. | ||
| 1797 | (widget-apply (widget-get widget :parent) :action event)) | ||
| 1798 | |||
| 1799 | ;;; The `radio-button' Widget. | 1937 | ;;; The `radio-button' Widget. |
| 1800 | 1938 | ||
| 1801 | (define-widget 'radio-button 'toggle | 1939 | (define-widget 'radio-button 'toggle |
| @@ -2017,7 +2155,7 @@ With optional ARG, move across that many fields." | |||
| 2017 | :value-create 'widget-editable-list-value-create | 2155 | :value-create 'widget-editable-list-value-create |
| 2018 | :value-delete 'widget-children-value-delete | 2156 | :value-delete 'widget-children-value-delete |
| 2019 | :value-get 'widget-editable-list-value-get | 2157 | :value-get 'widget-editable-list-value-get |
| 2020 | :validate 'widget-editable-list-validate | 2158 | :validate 'widget-children-validate |
| 2021 | :match 'widget-editable-list-match | 2159 | :match 'widget-editable-list-match |
| 2022 | :match-inline 'widget-editable-list-match-inline | 2160 | :match-inline 'widget-editable-list-match-inline |
| 2023 | :insert-before 'widget-editable-list-insert-before | 2161 | :insert-before 'widget-editable-list-insert-before |
| @@ -2062,16 +2200,6 @@ With optional ARG, move across that many fields." | |||
| 2062 | (apply 'append (mapcar (lambda (child) (widget-apply child :value-inline)) | 2200 | (apply 'append (mapcar (lambda (child) (widget-apply child :value-inline)) |
| 2063 | (widget-get widget :children)))) | 2201 | (widget-get widget :children)))) |
| 2064 | 2202 | ||
| 2065 | (defun widget-editable-list-validate (widget) | ||
| 2066 | ;; All the chilren must be valid. | ||
| 2067 | (let ((children (widget-get widget :children)) | ||
| 2068 | child found) | ||
| 2069 | (while (and children (not found)) | ||
| 2070 | (setq child (car children) | ||
| 2071 | children (cdr children) | ||
| 2072 | found (widget-apply child :validate))) | ||
| 2073 | found)) | ||
| 2074 | |||
| 2075 | (defun widget-editable-list-match (widget value) | 2203 | (defun widget-editable-list-match (widget value) |
| 2076 | ;; Value must be a list and all the members must match the type. | 2204 | ;; Value must be a list and all the members must match the type. |
| 2077 | (and (listp value) | 2205 | (and (listp value) |
| @@ -2195,7 +2323,7 @@ With optional ARG, move across that many fields." | |||
| 2195 | :value-create 'widget-group-value-create | 2323 | :value-create 'widget-group-value-create |
| 2196 | :value-delete 'widget-children-value-delete | 2324 | :value-delete 'widget-children-value-delete |
| 2197 | :value-get 'widget-editable-list-value-get | 2325 | :value-get 'widget-editable-list-value-get |
| 2198 | :validate 'widget-editable-list-validate | 2326 | :validate 'widget-children-validate |
| 2199 | :match 'widget-group-match | 2327 | :match 'widget-group-match |
| 2200 | :match-inline 'widget-group-match-inline) | 2328 | :match-inline 'widget-group-match-inline) |
| 2201 | 2329 | ||
| @@ -2284,19 +2412,14 @@ With optional ARG, move across that many fields." | |||
| 2284 | :format "%v\n%h" | 2412 | :format "%v\n%h" |
| 2285 | :documentation-property 'variable-documentation) | 2413 | :documentation-property 'variable-documentation) |
| 2286 | 2414 | ||
| 2287 | (define-widget 'string 'editable-field | ||
| 2288 | "A string" | ||
| 2289 | :prompt-value 'widget-string-prompt-value | ||
| 2290 | :tag "String" | ||
| 2291 | :format "%[%t%]: %v") | ||
| 2292 | |||
| 2293 | (defvar widget-string-prompt-value-history nil | 2415 | (defvar widget-string-prompt-value-history nil |
| 2294 | "History of input to `widget-string-prompt-value'.") | 2416 | "History of input to `widget-string-prompt-value'.") |
| 2295 | 2417 | ||
| 2296 | (defun widget-string-prompt-value (widget prompt value unbound) | 2418 | (define-widget 'string 'editable-field |
| 2297 | ;; Read a string. | 2419 | "A string" |
| 2298 | (read-string prompt (if unbound nil (cons value 1)) | 2420 | :tag "String" |
| 2299 | 'widget-string-prompt-value-history)) | 2421 | :format "%{%t%}: %v" |
| 2422 | :prompt-history 'widget-string-prompt-value-history) | ||
| 2300 | 2423 | ||
| 2301 | (define-widget 'regexp 'string | 2424 | (define-widget 'regexp 'string |
| 2302 | "A regular expression." | 2425 | "A regular expression." |
| @@ -2307,7 +2430,7 @@ With optional ARG, move across that many fields." | |||
| 2307 | (defun widget-regexp-match (widget value) | 2430 | (defun widget-regexp-match (widget value) |
| 2308 | ;; Match valid regexps. | 2431 | ;; Match valid regexps. |
| 2309 | (and (stringp value) | 2432 | (and (stringp value) |
| 2310 | (condition-case data | 2433 | (condition-case nil |
| 2311 | (prog1 t | 2434 | (prog1 t |
| 2312 | (string-match value "")) | 2435 | (string-match value "")) |
| 2313 | (error nil)))) | 2436 | (error nil)))) |
| @@ -2325,7 +2448,7 @@ With optional ARG, move across that many fields." | |||
| 2325 | "A file widget. | 2448 | "A file widget. |
| 2326 | It will read a file name from the minibuffer when activated." | 2449 | It will read a file name from the minibuffer when activated." |
| 2327 | :prompt-value 'widget-file-prompt-value | 2450 | :prompt-value 'widget-file-prompt-value |
| 2328 | :format "%[%t%]: %v" | 2451 | :format "%{%t%}: %v" |
| 2329 | :tag "File" | 2452 | :tag "File" |
| 2330 | :action 'widget-file-action) | 2453 | :action 'widget-file-action) |
| 2331 | 2454 | ||
| @@ -2334,7 +2457,7 @@ It will read a file name from the minibuffer when activated." | |||
| 2334 | (abbreviate-file-name | 2457 | (abbreviate-file-name |
| 2335 | (if unbound | 2458 | (if unbound |
| 2336 | (read-file-name prompt) | 2459 | (read-file-name prompt) |
| 2337 | (let ((prompt2 (concat prompt "(default `" value "') ")) | 2460 | (let ((prompt2 (format "%s (default %s) " prompt value)) |
| 2338 | (dir (file-name-directory value)) | 2461 | (dir (file-name-directory value)) |
| 2339 | (file (file-name-nondirectory value)) | 2462 | (file (file-name-nondirectory value)) |
| 2340 | (must-match (widget-get widget :must-match))) | 2463 | (must-match (widget-get widget :must-match))) |
| @@ -2358,11 +2481,18 @@ It will read a file name from the minibuffer when activated." | |||
| 2358 | It will read a directory name from the minibuffer when activated." | 2481 | It will read a directory name from the minibuffer when activated." |
| 2359 | :tag "Directory") | 2482 | :tag "Directory") |
| 2360 | 2483 | ||
| 2361 | (define-widget 'symbol 'string | 2484 | (defvar widget-symbol-prompt-value-history nil |
| 2485 | "History of input to `widget-symbol-prompt-value'.") | ||
| 2486 | |||
| 2487 | (define-widget 'symbol 'editable-field | ||
| 2362 | "A lisp symbol." | 2488 | "A lisp symbol." |
| 2363 | :value nil | 2489 | :value nil |
| 2364 | :tag "Symbol" | 2490 | :tag "Symbol" |
| 2491 | :format "%{%t%}: %v" | ||
| 2365 | :match (lambda (widget value) (symbolp value)) | 2492 | :match (lambda (widget value) (symbolp value)) |
| 2493 | :prompt-internal 'widget-symbol-prompt-internal | ||
| 2494 | :prompt-match 'symbolp | ||
| 2495 | :prompt-history 'widget-symbol-prompt-value-history | ||
| 2366 | :value-to-internal (lambda (widget value) | 2496 | :value-to-internal (lambda (widget value) |
| 2367 | (if (symbolp value) | 2497 | (if (symbolp value) |
| 2368 | (symbol-name value) | 2498 | (symbol-name value) |
| @@ -2372,24 +2502,48 @@ It will read a directory name from the minibuffer when activated." | |||
| 2372 | (intern value) | 2502 | (intern value) |
| 2373 | value))) | 2503 | value))) |
| 2374 | 2504 | ||
| 2505 | (defun widget-symbol-prompt-internal (widget prompt initial history) | ||
| 2506 | ;; Read file from minibuffer. | ||
| 2507 | (let ((answer (completing-read prompt obarray | ||
| 2508 | (widget-get widget :prompt-match) | ||
| 2509 | nil initial history))) | ||
| 2510 | (if (and (stringp answer) | ||
| 2511 | (not (zerop (length answer)))) | ||
| 2512 | answer | ||
| 2513 | (error "No value")))) | ||
| 2514 | |||
| 2515 | (defvar widget-function-prompt-value-history nil | ||
| 2516 | "History of input to `widget-function-prompt-value'.") | ||
| 2517 | |||
| 2375 | (define-widget 'function 'sexp | 2518 | (define-widget 'function 'sexp |
| 2376 | ;; Should complete on functions. | ||
| 2377 | "A lisp function." | 2519 | "A lisp function." |
| 2520 | :prompt-value 'widget-field-prompt-value | ||
| 2521 | :prompt-internal 'widget-symbol-prompt-internal | ||
| 2522 | :prompt-match 'fboundp | ||
| 2523 | :prompt-history 'widget-function-prompt-value-history | ||
| 2524 | :action 'widget-field-action | ||
| 2378 | :tag "Function") | 2525 | :tag "Function") |
| 2379 | 2526 | ||
| 2527 | (defvar widget-variable-prompt-value-history nil | ||
| 2528 | "History of input to `widget-variable-prompt-value'.") | ||
| 2529 | |||
| 2380 | (define-widget 'variable 'symbol | 2530 | (define-widget 'variable 'symbol |
| 2381 | ;; Should complete on variables. | 2531 | ;; Should complete on variables. |
| 2382 | "A lisp variable." | 2532 | "A lisp variable." |
| 2533 | :prompt-match 'boundp | ||
| 2534 | :prompt-history 'widget-variable-prompt-value-history | ||
| 2383 | :tag "Variable") | 2535 | :tag "Variable") |
| 2384 | 2536 | ||
| 2385 | (define-widget 'sexp 'string | 2537 | (define-widget 'sexp 'editable-field |
| 2386 | "An arbitrary lisp expression." | 2538 | "An arbitrary lisp expression." |
| 2387 | :tag "Lisp expression" | 2539 | :tag "Lisp expression" |
| 2540 | :format "%{%t%}: %v" | ||
| 2388 | :value nil | 2541 | :value nil |
| 2389 | :validate 'widget-sexp-validate | 2542 | :validate 'widget-sexp-validate |
| 2390 | :match (lambda (widget value) t) | 2543 | :match (lambda (widget value) t) |
| 2391 | :value-to-internal 'widget-sexp-value-to-internal | 2544 | :value-to-internal 'widget-sexp-value-to-internal |
| 2392 | :value-to-external (lambda (widget value) (read value)) | 2545 | :value-to-external (lambda (widget value) (read value)) |
| 2546 | :prompt-history 'widget-sexp-prompt-value-history | ||
| 2393 | :prompt-value 'widget-sexp-prompt-value) | 2547 | :prompt-value 'widget-sexp-prompt-value) |
| 2394 | 2548 | ||
| 2395 | (defun widget-sexp-value-to-internal (widget value) | 2549 | (defun widget-sexp-value-to-internal (widget value) |
| @@ -2430,18 +2584,19 @@ It will read a directory name from the minibuffer when activated." | |||
| 2430 | (defun widget-sexp-prompt-value (widget prompt value unbound) | 2584 | (defun widget-sexp-prompt-value (widget prompt value unbound) |
| 2431 | ;; Read an arbitrary sexp. | 2585 | ;; Read an arbitrary sexp. |
| 2432 | (let ((found (read-string prompt | 2586 | (let ((found (read-string prompt |
| 2433 | (if unbound nil (cons (prin1-to-string value) 1)) | 2587 | (if unbound nil (cons (prin1-to-string value) 0)) |
| 2434 | 'widget-sexp-prompt-value))) | 2588 | (widget-get widget :prompt-history)))) |
| 2435 | (let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*")))) | 2589 | (save-excursion |
| 2436 | (erase-buffer) | 2590 | (let ((buffer (set-buffer (get-buffer-create " *Widget Scratch*")))) |
| 2437 | (insert found) | 2591 | (erase-buffer) |
| 2438 | (goto-char (point-min)) | 2592 | (insert found) |
| 2439 | (let ((answer (read buffer))) | 2593 | (goto-char (point-min)) |
| 2440 | (unless (eobp) | 2594 | (let ((answer (read buffer))) |
| 2441 | (error "Junk at end of expression: %s" | 2595 | (unless (eobp) |
| 2442 | (buffer-substring (point) (point-max)))) | 2596 | (error "Junk at end of expression: %s" |
| 2443 | answer)))) | 2597 | (buffer-substring (point) (point-max)))) |
| 2444 | 2598 | answer))))) | |
| 2599 | |||
| 2445 | (define-widget 'integer 'sexp | 2600 | (define-widget 'integer 'sexp |
| 2446 | "An integer." | 2601 | "An integer." |
| 2447 | :tag "Integer" | 2602 | :tag "Integer" |
| @@ -2453,7 +2608,7 @@ It will read a directory name from the minibuffer when activated." | |||
| 2453 | value)) | 2608 | value)) |
| 2454 | :match (lambda (widget value) (integerp value))) | 2609 | :match (lambda (widget value) (integerp value))) |
| 2455 | 2610 | ||
| 2456 | (define-widget 'character 'string | 2611 | (define-widget 'character 'editable-field |
| 2457 | "An character." | 2612 | "An character." |
| 2458 | :tag "Character" | 2613 | :tag "Character" |
| 2459 | :value 0 | 2614 | :value 0 |
| @@ -2462,14 +2617,17 @@ It will read a directory name from the minibuffer when activated." | |||
| 2462 | :valid-regexp "\\`.\\'" | 2617 | :valid-regexp "\\`.\\'" |
| 2463 | :error "This field should contain a single character" | 2618 | :error "This field should contain a single character" |
| 2464 | :value-to-internal (lambda (widget value) | 2619 | :value-to-internal (lambda (widget value) |
| 2465 | (if (integerp value) | 2620 | (if (stringp value) |
| 2466 | (char-to-string value) | 2621 | value |
| 2467 | value)) | 2622 | (char-to-string value))) |
| 2468 | :value-to-external (lambda (widget value) | 2623 | :value-to-external (lambda (widget value) |
| 2469 | (if (stringp value) | 2624 | (if (stringp value) |
| 2470 | (aref value 0) | 2625 | (aref value 0) |
| 2471 | value)) | 2626 | value)) |
| 2472 | :match (lambda (widget value) (integerp value))) | 2627 | :match (lambda (widget value) |
| 2628 | (if (fboundp 'characterp) | ||
| 2629 | (characterp value) | ||
| 2630 | (integerp value)))) | ||
| 2473 | 2631 | ||
| 2474 | (define-widget 'number 'sexp | 2632 | (define-widget 'number 'sexp |
| 2475 | "A floating point number." | 2633 | "A floating point number." |
| @@ -2518,12 +2676,56 @@ It will read a directory name from the minibuffer when activated." | |||
| 2518 | (define-widget 'choice 'menu-choice | 2676 | (define-widget 'choice 'menu-choice |
| 2519 | "A union of several sexp types." | 2677 | "A union of several sexp types." |
| 2520 | :tag "Choice" | 2678 | :tag "Choice" |
| 2521 | :format "%[%t%]: %v") | 2679 | :format "%[%t%]: %v" |
| 2680 | :prompt-value 'widget-choice-prompt-value) | ||
| 2681 | |||
| 2682 | (defun widget-choice-prompt-value (widget prompt value unbound) | ||
| 2683 | "Make a choice." | ||
| 2684 | (let ((args (widget-get widget :args)) | ||
| 2685 | (completion-ignore-case (widget-get widget :case-fold)) | ||
| 2686 | current choices old) | ||
| 2687 | ;; Find the first arg that match VALUE. | ||
| 2688 | (let ((look args)) | ||
| 2689 | (while look | ||
| 2690 | (if (widget-apply (car look) :match value) | ||
| 2691 | (setq old (car look) | ||
| 2692 | look nil) | ||
| 2693 | (setq look (cdr look))))) | ||
| 2694 | ;; Find new choice. | ||
| 2695 | (setq current | ||
| 2696 | (cond ((= (length args) 0) | ||
| 2697 | nil) | ||
| 2698 | ((= (length args) 1) | ||
| 2699 | (nth 0 args)) | ||
| 2700 | ((and (= (length args) 2) | ||
| 2701 | (memq old args)) | ||
| 2702 | (if (eq old (nth 0 args)) | ||
| 2703 | (nth 1 args) | ||
| 2704 | (nth 0 args))) | ||
| 2705 | (t | ||
| 2706 | (while args | ||
| 2707 | (setq current (car args) | ||
| 2708 | args (cdr args)) | ||
| 2709 | (setq choices | ||
| 2710 | (cons (cons (widget-apply current :menu-tag-get) | ||
| 2711 | current) | ||
| 2712 | choices))) | ||
| 2713 | (let ((val (completing-read prompt choices nil t))) | ||
| 2714 | (if (stringp val) | ||
| 2715 | (let ((try (try-completion val choices))) | ||
| 2716 | (when (stringp try) | ||
| 2717 | (setq val try)) | ||
| 2718 | (cdr (assoc val choices))) | ||
| 2719 | nil))))) | ||
| 2720 | (if current | ||
| 2721 | (widget-prompt-value current prompt nil t) | ||
| 2722 | value))) | ||
| 2522 | 2723 | ||
| 2523 | (define-widget 'radio 'radio-button-choice | 2724 | (define-widget 'radio 'radio-button-choice |
| 2524 | "A union of several sexp types." | 2725 | "A union of several sexp types." |
| 2525 | :tag "Choice" | 2726 | :tag "Choice" |
| 2526 | :format "%{%t%}:\n%v") | 2727 | :format "%{%t%}:\n%v" |
| 2728 | :prompt-value 'widget-choice-prompt-value) | ||
| 2527 | 2729 | ||
| 2528 | (define-widget 'repeat 'editable-list | 2730 | (define-widget 'repeat 'editable-list |
| 2529 | "A variable length homogeneous list." | 2731 | "A variable length homogeneous list." |
| @@ -2539,18 +2741,11 @@ It will read a directory name from the minibuffer when activated." | |||
| 2539 | "To be nil or non-nil, that is the question." | 2741 | "To be nil or non-nil, that is the question." |
| 2540 | :tag "Boolean" | 2742 | :tag "Boolean" |
| 2541 | :prompt-value 'widget-boolean-prompt-value | 2743 | :prompt-value 'widget-boolean-prompt-value |
| 2542 | :format "%{%t%}: %[%v%]\n") | 2744 | :format "%[%t%]: %v\n") |
| 2543 | 2745 | ||
| 2544 | (defun widget-boolean-prompt-value (widget prompt value unbound) | 2746 | (defun widget-boolean-prompt-value (widget prompt value unbound) |
| 2545 | ;; Toggle a boolean. | 2747 | ;; Toggle a boolean. |
| 2546 | (cond (unbound | 2748 | (y-or-n-p prompt)) |
| 2547 | (y-or-n-p prompt)) | ||
| 2548 | (value | ||
| 2549 | (message "Off") | ||
| 2550 | nil) | ||
| 2551 | (t | ||
| 2552 | (message "On") | ||
| 2553 | t))) | ||
| 2554 | 2749 | ||
| 2555 | ;;; The `color' Widget. | 2750 | ;;; The `color' Widget. |
| 2556 | 2751 | ||
diff --git a/lisp/widget.el b/lisp/widget.el index 4905c06b70a..f65b6603615 100644 --- a/lisp/widget.el +++ b/lisp/widget.el | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | ;; | 4 | ;; |
| 5 | ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> | 5 | ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> |
| 6 | ;; Keywords: help, extensions, faces, hypermedia | 6 | ;; Keywords: help, extensions, faces, hypermedia |
| 7 | ;; Version: 1.90 | 7 | ;; Version: 1.97 |
| 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. |
| @@ -44,7 +44,10 @@ | |||
| 44 | (set (car keywords) (car keywords))) | 44 | (set (car keywords) (car keywords))) |
| 45 | (setq keywords (cdr keywords))))))) | 45 | (setq keywords (cdr keywords))))))) |
| 46 | 46 | ||
| 47 | (define-widget-keywords :prompt-value :text-format :deactivate :active | 47 | (define-widget-keywords :mouse-down-action :glyph-up :glyph-down |
| 48 | :glyph-inactive | ||
| 49 | :prompt-internal :prompt-history :prompt-match | ||
| 50 | :prompt-value :text-format :deactivate :active | ||
| 48 | :inactive :activate :sibling-args :delete-button-args | 51 | :inactive :activate :sibling-args :delete-button-args |
| 49 | :insert-button-args :append-button-args :button-args | 52 | :insert-button-args :append-button-args :button-args |
| 50 | :tag-glyph :off-glyph :on-glyph :valid-regexp | 53 | :tag-glyph :off-glyph :on-glyph :valid-regexp |