diff lisp/w3/widget-edit.el @ 16:0293115a14e9 r19-15b91

Import from CVS: tag r19-15b91
author cvs
date Mon, 13 Aug 2007 08:49:20 +0200
parents 9ee227acff29
children
line wrap: on
line diff
--- a/lisp/w3/widget-edit.el	Mon Aug 13 08:48:43 2007 +0200
+++ b/lisp/w3/widget-edit.el	Mon Aug 13 08:49:20 2007 +0200
@@ -4,7 +4,7 @@
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: extensions
-;; Version: 1.13
+;; Version: 1.22
 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
 
 ;;; Commentary:
@@ -58,14 +58,23 @@
 
 ;;; Compatibility.
 
-(or (fboundp 'event-point)
-    ;; XEmacs function missing in Emacs.
-    (defun event-point (event)
-      "Return the character position of the given mouse-motion, button-press,
+(unless (fboundp 'event-point)
+  ;; XEmacs function missing in Emacs.
+  (defun event-point (event)
+    "Return the character position of the given mouse-motion, button-press,
 or button-release event.  If the event did not occur over a window, or did
 not occur over text, then this returns nil.  Otherwise, it returns an index
 into the buffer visible in the event's window."
-      (posn-point (event-start event))))
+    (posn-point (event-start event))))
+
+(unless (fboundp 'error-message-string)
+  ;; Emacs function missing in XEmacs.
+  (defun error-message-string (obj)
+    "Convert an error value to an error message."
+    (let ((buf (get-buffer-create " *error-message*")))
+      (erase-buffer buf)
+      (display-error obj buf)
+      (buffer-string buf))))
 
 ;;; Customization.
 
@@ -77,7 +86,13 @@
   :prefix "widget-"
   :group 'emacs)
 
-(defface widget-documentation-face '((t ()))
+(defface widget-documentation-face '((((class color)
+				       (background dark))
+				      (:foreground "lime green"))
+				     (((class color)
+				       (background light))
+				      (:foreground "dark green"))
+				     (t nil))
   "Face used for documentation text."
   :group 'widgets)
 
@@ -90,12 +105,10 @@
   :type 'face
   :group 'widgets)
 
-(defface widget-field-face '((((type x)
-			       (class grayscale color)
+(defface widget-field-face '((((class grayscale color)
 			       (background light))
 			      (:background "light gray"))
-			     (((type x)
-			       (class grayscale color)
+			     (((class grayscale color)
 			       (background dark))
 			      (:background "dark gray"))
 			     (t 
@@ -106,6 +119,7 @@
 (defcustom widget-menu-max-size 40
   "Largest number of items allowed in a popup-menu.
 Larger menus are read through the minibuffer."
+  :group 'widgets
   :type 'integer)
 
 ;;; Utility functions.
@@ -236,15 +250,47 @@
 (defun widget-specify-field-update (widget from to)
   ;; Specify editable button for WIDGET between FROM and TO.
   (let ((map (widget-get widget :keymap))
+	(secret (widget-get widget :secret))
+	(secret-to to)
+	(size (widget-get widget :size))
 	(face (or (widget-get widget :value-face)
 		  'widget-field-face)))
+
+    (when secret 
+      (while (and size
+		  (not (zerop size))
+		  (> secret-to from)
+		  (eq (char-after (1- secret-to)) ?\ ))
+	(setq secret-to (1- secret-to)))
+
+      (save-excursion
+	(goto-char from)
+	(while (< (point) secret-to)
+	  (let ((old (get-text-property (point) 'secret)))
+	    (when old
+	      (subst-char-in-region (point) (1+ (point)) secret old)))
+	  (forward-char))))
+
     (set-text-properties from to (list 'field widget
 				       'read-only nil
 				       'keymap map
 				       'local-map map
 				       'face face))
+
+    (when secret 
+      (save-excursion
+	(goto-char from)
+	(while (< (point) secret-to)
+	  (let ((old (following-char)))
+	    (subst-char-in-region (point) (1+ (point)) old secret)
+	    (put-text-property (point) (1+ (point)) 'secret old))
+	  (forward-char))))
+
     (unless (widget-get widget :size)
-      (put-text-property to (1+ to) 'face face))))
+      (add-text-properties to (1+ to) (list 'field widget
+					    'face face
+					    'local-map map
+					    'keymap map)))))
 
 (defun widget-specify-button (widget from to)
   ;; Specify button for WIDGET between FROM and TO.
@@ -255,6 +301,14 @@
 				       'end-open t
 				       'face face))))
 
+(defun widget-specify-sample (widget from to)
+  ;; Specify sample for WIDGET between FROM and TO.
+  (let ((face (widget-apply widget :sample-face-get)))
+    (when face
+      (add-text-properties from to (list 'start-open t
+					 'end-open t
+					 'face face)))))
+
 (defun widget-specify-doc (widget from to)
   ;; Specify documentation for WIDGET between FROM and TO.
   (add-text-properties from to (list 'widget-doc widget
@@ -435,10 +489,8 @@
   "Keymap containing useful binding for buffers containing widgets.
 Recommended as a parent keymap for modes using widgets.")
 
-(if widget-keymap 
-    ()
+(unless widget-keymap 
   (setq widget-keymap (make-sparse-keymap))
-  (set-keymap-parent widget-keymap global-map)
   (define-key widget-keymap "\t" 'widget-forward)
   (define-key widget-keymap "\M-\t" 'widget-backward)
   (define-key widget-keymap [(shift tab)] 'widget-backward)
@@ -454,6 +506,30 @@
   "Keymap used for events the widget does not handle themselves.")
 (make-variable-buffer-local 'widget-global-map)
 
+(defvar widget-field-keymap nil
+  "Keymap used inside an editable field.")
+
+(unless widget-field-keymap 
+  (setq widget-field-keymap (copy-keymap widget-keymap))
+  (define-key widget-field-keymap "\C-m" 'widget-field-activate)
+  (set-keymap-parent widget-field-keymap global-map))
+
+(defvar widget-text-keymap nil
+  "Keymap used inside a text field.")
+
+(unless widget-text-keymap 
+  (setq widget-text-keymap (copy-keymap widget-keymap))
+  (set-keymap-parent widget-text-keymap global-map))
+
+(defun widget-field-activate (pos &optional event)
+  "Activate the ediable field at point."
+  (interactive "@d")
+  (let* ((field (get-text-property pos 'field)))
+    (if field
+	(widget-apply field :action event)
+      (call-interactively
+       (lookup-key widget-global-map (this-command-keys))))))
+
 (defun widget-button-click (event)
   "Activate button below mouse pointer."
   (interactive "@e")
@@ -468,10 +544,9 @@
       (call-interactively
        (lookup-key widget-global-map (this-command-keys))))))
 
-(defun widget-forward (arg)
-  "Move point to the next field or button.
-With optional ARG, move across that many fields."
-  (interactive "p")
+(defun widget-move (arg)
+  "Move point to the ARG next field or button.
+ARG may be negative to move backward."
   (while (> arg 0)
     (setq arg (1- arg))
     (let ((next (cond ((get-text-property (point) 'button)
@@ -533,13 +608,22 @@
 	     (goto-char (max button field)))
 	    (button (goto-char button))
 	    (field (goto-char field)))))
-  (widget-echo-help (point)))
+  (widget-echo-help (point))
+  (run-hooks 'widget-move-hook))
+
+(defun widget-forward (arg)
+  "Move point to the next field or button.
+With optional ARG, move across that many fields."
+  (interactive "p")
+  (run-hooks 'widget-forward-hook)
+  (widget-move arg))
 
 (defun widget-backward (arg)
   "Move point to the previous field or button.
 With optional ARG, move across that many fields."
   (interactive "p")
-  (widget-forward (- arg)))
+  (run-hooks 'widget-backward-hook)
+  (widget-move (- arg)))
 
 ;;; Setting up the buffer.
 
@@ -665,6 +749,7 @@
   :offset 0
   :format-handler 'widget-default-format-handler
   :button-face-get 'widget-default-button-face-get 
+  :sample-face-get 'widget-default-sample-face-get 
   :delete 'widget-default-delete
   :value-set 'widget-default-value-set
   :value-inline 'widget-default-value-inline
@@ -680,6 +765,7 @@
 	 (tag (widget-get widget :tag))
 	 (doc (widget-get widget :doc))
 	 button-begin button-end
+	 sample-begin sample-end
 	 doc-begin doc-end
 	 value-pos)
      (insert (widget-get widget :format))
@@ -694,6 +780,10 @@
 		(setq button-begin (point)))
 	       ((eq escape ?\])
 		(setq button-end (point)))
+	       ((eq escape ?\{)
+		(setq sample-begin (point)))
+	       ((eq escape ?\})
+		(setq sample-end (point)))
 	       ((eq escape ?n)
 		(when (widget-get widget :indent)
 		  (insert "\n")
@@ -717,9 +807,11 @@
 		  (setq value-pos (point))))
 	       (t 
 		(widget-apply widget :format-handler escape)))))
-     ;; Specify button and doc, and insert value.
+     ;; Specify button, sample, and doc, and insert value.
      (and button-begin button-end
 	  (widget-specify-button widget button-begin button-end))
+     (and sample-begin sample-end
+	  (widget-specify-sample widget sample-begin sample-end))
      (and doc-begin doc-end
 	  (widget-specify-doc widget doc-begin doc-end))
      (when value-pos
@@ -778,6 +870,10 @@
   ;; Use :button-face or widget-button-face
   (or (widget-get widget :button-face) 'widget-button-face))
 
+(defun widget-default-sample-face-get (widget)
+  ;; Use :sample-face.
+  (widget-get widget :sample-face))
+
 (defun widget-default-delete (widget)
   ;; Remove widget from the buffer.
   (let ((from (widget-get widget :from))
@@ -877,6 +973,7 @@
 
 (define-widget 'link 'item
   "An embedded link."
+  :help-echo "Push me to follow the link."
   :format "%[_%t_%]")
 
 ;;; The `info-link' Widget.
@@ -905,6 +1002,7 @@
 (define-widget 'editable-field 'default
   "An editable text field."
   :convert-widget 'widget-item-convert-widget
+  :keymap widget-field-keymap
   :format "%v"
   :value ""
   :action 'widget-field-action
@@ -965,6 +1063,7 @@
   (let ((from (widget-get widget :value-from))
 	(to (widget-get widget :value-to))
 	(size (widget-get widget :size))
+	(secret (widget-get widget :secret))
 	(old (current-buffer)))
     (if (and from to)
 	(progn 
@@ -976,8 +1075,15 @@
 		      (> to from)
 		      (eq (char-after (1- to)) ?\ ))
 	    (setq to (1- to)))
-	  (prog1 (buffer-substring-no-properties from to)
-	    (set-buffer old)))
+	  (let ((result (buffer-substring-no-properties from to)))
+	    (when secret
+	      (let ((index 0))
+		(while (< (+ from index) to)
+		  (aset result index
+			(get-text-property (+ from index) 'secret))
+		  (setq index (1+ index)))))
+	    (set-buffer old)
+	    result))
       (widget-get widget :value))))
 
 (defun widget-field-match (widget value)
@@ -987,6 +1093,7 @@
 ;;; The `text' Widget.
 
 (define-widget 'text 'editable-field
+  :keymap widget-text-keymap
   "A multiline text area.")
 
 ;;; The `menu-choice' Widget.
@@ -1873,7 +1980,7 @@
   :tag "Character"
   :value 0
   :size 1 
-  :format "%t: %v\n"
+  :format "%{%t%}: %v\n"
   :type-error "This field should contain a character"
   :value-to-internal (lambda (widget value)
 		       (if (integerp value) 
@@ -1899,12 +2006,12 @@
 (define-widget 'list 'group
   "A lisp list."
   :tag "List"
-  :format "%t:\n%v")
+  :format "%{%t%}:\n%v")
 
 (define-widget 'vector 'group
   "A lisp vector."
   :tag "Vector"
-  :format "%t:\n%v"
+  :format "%{%t%}:\n%v"
   :match 'widget-vector-match
   :value-to-internal (lambda (widget value) (append value nil))
   :value-to-external (lambda (widget value) (apply 'vector value)))
@@ -1917,7 +2024,7 @@
 (define-widget 'cons 'group
   "A cons-cell."
   :tag "Cons-cell"
-  :format "%t:\n%v"
+  :format "%{%t%}:\n%v"
   :match 'widget-cons-match
   :value-to-internal (lambda (widget value)
 		       (list (car value) (cdr value)))
@@ -1937,22 +2044,22 @@
 (define-widget 'radio 'radio-button-choice
   "A union of several sexp types."
   :tag "Choice"
-  :format "%t:\n%v")
+  :format "%{%t%}:\n%v")
 
 (define-widget 'repeat 'editable-list
   "A variable length homogeneous list."
   :tag "Repeat"
-  :format "%t:\n%v%i\n")
+  :format "%{%t%}:\n%v%i\n")
 
 (define-widget 'set 'checklist
   "A list of members from a fixed set."
   :tag "Set"
-  :format "%t:\n%v")
+  :format "%{%t%}:\n%v")
 
 (define-widget 'boolean 'toggle
   "To be nil or non-nil, that is the question."
   :tag "Boolean"
-  :format "%t: %v")
+  :format "%{%t%}: %v")
 
 ;;; The `color' Widget.