Don't call turn_on_atimers around `connect' (Bug#5723).
[bpt/emacs.git] / lisp / wid-edit.el
index 5de5f2d..6296a96 100644 (file)
@@ -1,7 +1,7 @@
 ;;; wid-edit.el --- Functions for creating and using widgets -*-byte-compile-dynamic: t;-*-
 ;;
 ;; Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-;;   2006, 2007, 2008, 2009  Free Software Foundation, Inc.
+;;   2006, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Maintainer: FSF
@@ -78,8 +78,7 @@
   :link '(custom-manual "(widget)Top")
   :link '(emacs-library-link :tag "Lisp File" "widget.el")
   :prefix "widget-"
-  :group 'extensions
-  :group 'hypermedia)
+  :group 'extensions)
 
 (defgroup widget-documentation nil
   "Options controlling the display of documentation strings."
@@ -104,8 +103,8 @@ This exists as a variable so it can be set locally in certain buffers.")
   "Face used for documentation text."
   :group 'widget-documentation
   :group 'widget-faces)
-;; backward compatibility alias
-(put 'widget-documentation-face 'face-alias 'widget-documentation)
+(define-obsolete-face-alias 'widget-documentation-face
+  'widget-documentation "22.1")
 
 (defvar widget-button-face 'widget-button
   "Face used for buttons in widgets.
@@ -114,8 +113,7 @@ This exists as a variable so it can be set locally in certain buffers.")
 (defface widget-button '((t (:weight bold)))
   "Face used for widget buttons."
   :group 'widget-faces)
-;; backward compatibility alias
-(put 'widget-button-face 'face-alias 'widget-button)
+(define-obsolete-face-alias 'widget-button-face 'widget-button "22.1")
 
 (defcustom widget-mouse-face 'highlight
   "Face used for widget buttons when the mouse is above them."
@@ -138,8 +136,7 @@ This exists as a variable so it can be set locally in certain buffers.")
                         :slant italic))
   "Face used for editable fields."
   :group 'widget-faces)
-;; backward-compatibility alias
-(put 'widget-field-face 'face-alias 'widget-field)
+(define-obsolete-face-alias 'widget-field-face 'widget-field "22.1")
 
 (defface widget-single-line-field '((((type tty))
                                     :background "green3"
@@ -154,8 +151,8 @@ This exists as a variable so it can be set locally in certain buffers.")
                                     :slant italic))
   "Face used for editable fields spanning only a single line."
   :group 'widget-faces)
-;; backward-compatibility alias
-(put 'widget-single-line-field-face 'face-alias 'widget-single-line-field)
+(define-obsolete-face-alias 'widget-single-line-field-face
+  'widget-single-line-field "22.1")
 
 ;;; This causes display-table to be loaded, and not usefully.
 ;;;(defvar widget-single-line-display-table
@@ -342,16 +339,12 @@ new value.")
         (or (not widget-field-add-space) (widget-get widget :size))))
     (if (functionp help-echo)
       (setq help-echo 'widget-mouse-help))
-    (when (and (> to (1+ from))
-              (= (char-before to) ?\n))
+    (when (= (char-before to) ?\n)
       ;; When the last character in the field is a newline, we want to
       ;; give it a `field' char-property of `boundary', which helps the
       ;; C-n/C-p act more naturally when entering/leaving the field.  We
-      ;; do this by making a small secondary overlay to contain just that
+     ;; do this by making a small secondary overlay to contain just that
       ;; one character.
-      ;; We DON'T do this if the field just consists of a newline, eg
-      ;; when specifying a character, since it breaks things (below
-      ;; does 1- to, which results in to = from).  Bug#2689.
       (let ((overlay (make-overlay (1- to) to nil t nil)))
        (overlay-put overlay 'field 'boundary)
         ;; We need the real field for tabbing.
@@ -459,8 +452,8 @@ new value.")
   '((t :inherit shadow))
   "Face used for inactive widgets."
   :group 'widget-faces)
-;; backward-compatibility alias
-(put 'widget-inactive-face 'face-alias 'widget-inactive)
+(define-obsolete-face-alias 'widget-inactive-face
+  'widget-inactive "22.1")
 
 (defun widget-specify-inactive (widget from to)
   "Make WIDGET inactive for user modifications."
@@ -645,8 +638,7 @@ extension (xpm, xbm, gif, jpg, or png) located in
           (dolist (elt widget-image-conversion)
             (dolist (ext (cdr elt))
               (push (list :type (car elt) :file (concat image ext)) specs)))
-          (setq specs (nreverse specs))
-          (find-image specs)))
+          (find-image (nreverse specs))))
        (t
         ;; Oh well.
         nil)))
@@ -663,7 +655,7 @@ IMAGE should either be an image or an image file name sans extension
 
 Optional arguments DOWN and INACTIVE are used instead of IMAGE when the
 button is pressed or inactive, respectively.  These are currently ignored."
-  (if (and (display-graphic-p)
+  (if (and (featurep 'image)
           (setq image (widget-image-find image)))
       (progn (widget-put widget :suppress-face t)
             (insert-image image tag))
@@ -863,14 +855,16 @@ button end points."
 ;; This alias exists only so that one can choose in doc-strings (e.g.
 ;; Custom-mode) which key-binding of widget-keymap one wants to refer to.
 ;; http://lists.gnu.org/archive/html/emacs-devel/2008-11/msg00480.html
-(defalias 'advertised-widget-backward 'widget-backward)
+(define-obsolete-function-alias 'advertised-widget-backward
+  'widget-backward "23.2")
 
 ;;;###autoload
 (defvar widget-keymap
   (let ((map (make-sparse-keymap)))
     (define-key map "\t" 'widget-forward)
     (define-key map "\e\t" 'widget-backward)
-    (define-key map [(shift tab)] 'advertised-widget-backward)
+    (define-key map [(shift tab)] 'widget-backward)
+    (put 'widget-backward :advertised-binding [(shift tab)])
     (define-key map [backtab] 'widget-backward)
     (define-key map [down-mouse-2] 'widget-button-click)
     (define-key map [down-mouse-1] 'widget-button-click)
@@ -879,7 +873,8 @@ button end points."
     (define-key map [(control ?m)] 'widget-button-press)
     map)
   "Keymap containing useful binding for buffers containing widgets.
-Recommended as a parent keymap for modes using widgets.")
+Recommended as a parent keymap for modes using widgets.
+Note that such modes will need to require wid-edit.")
 
 (defvar widget-global-map global-map
   "Keymap used for events a widget does not handle itself.")
@@ -924,8 +919,8 @@ Recommended as a parent keymap for modes using widgets.")
      (:weight bold :underline t)))
   "Face used for pressed buttons."
   :group 'widget-faces)
-;; backward-compatibility alias
-(put 'widget-button-pressed-face 'face-alias 'widget-button-pressed)
+(define-obsolete-face-alias 'widget-button-pressed-face
+  'widget-button-pressed "22.1")
 
 (defvar widget-button-click-moves-point nil
   "If non-nil, `widget-button-click' moves point to a button after invoking it.
@@ -1164,11 +1159,9 @@ the field."
 When not inside a field, move to the previous button or field."
   (interactive)
   (let ((field (widget-field-find (point))))
-    (if field
-       (save-restriction
-         (widget-narrow-to-field)
-         (widget-apply field :complete))
-         (error "Not in an editable field"))))
+    (when field
+      (widget-apply field :complete))
+    (error "Not in an editable field")))
 
 ;;; Setting up the buffer.
 
@@ -1261,6 +1254,19 @@ When not inside a field, move to the previous button or field."
             (overlay-end overlay)))
       (cdr overlay))))
 
+(defun widget-field-text-end (widget)
+  (let ((to   (widget-field-end widget))
+       (size (widget-get widget :size)))
+    (if (or (null size) (zerop size))
+        to
+      (let ((from (widget-field-start widget)))
+        (if (and from to)
+            (with-current-buffer (widget-field-buffer widget)
+              (while (and (> to from)
+                          (eq (char-after (1- to)) ?\s))
+                (setq to (1- to)))
+              to))))))
+
 (defun widget-field-find (pos)
   "Return the field at POS.
 Unlike (get-char-property POS 'field), this works with empty fields too."
@@ -1866,6 +1872,7 @@ by some other text in the `:format' string (if specified)."
   :valid-regexp ""
   :error "Field's value doesn't match allowed forms"
   :value-create 'widget-field-value-create
+  :value-set 'widget-field-value-set
   :value-delete 'widget-field-value-delete
   :value-get 'widget-field-value-get
   :match 'widget-field-match)
@@ -1904,6 +1911,18 @@ the earlier input."
                        (widget-apply widget :value-get))
     widget))
 
+(defun widget-field-value-set (widget value)
+  "Set an editable text field WIDGET to VALUE"
+  (let ((from (widget-field-start widget))
+       (to (widget-field-text-end widget))
+       (buffer (widget-field-buffer widget))
+       (size (widget-get widget :size)))
+    (when (and from to (buffer-live-p buffer))
+      (with-current-buffer buffer
+       (goto-char from)
+       (delete-char (- to from))
+       (insert value)))))
+
 (defun widget-field-value-create (widget)
   "Create an editable text field."
   (let ((size (widget-get widget :size))
@@ -1939,21 +1958,13 @@ the earlier input."
 (defun widget-field-value-get (widget)
   "Return current text in editing field."
   (let ((from (widget-field-start widget))
-       (to (widget-field-end widget))
+       (to (widget-field-text-end widget))
        (buffer (widget-field-buffer widget))
-       (size (widget-get widget :size))
        (secret (widget-get widget :secret))
        (old (current-buffer)))
     (if (and from to)
        (progn
          (set-buffer buffer)
-         (while (and size
-                     (not (zerop size))
-                     ;; Bug#2689.  Don't allow this loop to reduce a
-                     ;; character field to zero size if it contains a space.
-                     (> to (1+ from))
-                     (eq (char-after (1- to)) ?\s))
-           (setq to (1- to)))
          (let ((result (buffer-substring-no-properties from to)))
            (when secret
              (let ((index 0))
@@ -2805,11 +2816,19 @@ Return an alist of (TYPE MATCH)."
 ;;; The `visibility' Widget.
 
 (define-widget 'visibility 'item
-  "An indicator and manipulator for hidden items."
+  "An indicator and manipulator for hidden items.
+
+The following properties have special meanings for this widget:
+:on-image  Image filename or spec to display when the item is visible.
+:on        Text shown if the \"on\" image is nil or cannot be displayed.
+:off-image Image filename or spec to display when the item is hidden.
+:off       Text shown if the \"off\" image is nil cannot be displayed."
   :format "%[%v%]"
   :button-prefix ""
   :button-suffix ""
+  :on-image "down"
   :on "Hide"
+  :off-image "right"
   :off "Show"
   :value-create 'widget-visibility-value-create
   :action 'widget-toggle-action
@@ -2817,21 +2836,17 @@ Return an alist of (TYPE MATCH)."
 
 (defun widget-visibility-value-create (widget)
   ;; Insert text representing the `on' and `off' states.
-  (let ((on (widget-get widget :on))
-       (off (widget-get widget :off)))
-    (if on
-       (setq on (concat widget-push-button-prefix
-                        on
-                        widget-push-button-suffix))
-      (setq on ""))
-    (if off
-       (setq off (concat widget-push-button-prefix
-                         off
-                         widget-push-button-suffix))
-      (setq off ""))
-    (if (widget-value widget)
-       (widget-image-insert widget on "down" "down-pushed")
-      (widget-image-insert widget off "right" "right-pushed"))))
+  (let* ((val (widget-value widget))
+        (text (widget-get widget (if val :on :off)))
+        (img (widget-image-find
+              (widget-get widget (if val :on-image :off-image)))))
+    (widget-image-insert widget
+                        (if text
+                            (concat widget-push-button-prefix text
+                                    widget-push-button-suffix)
+                          "")
+                        (if img
+                            (append img '(:ascent center))))))
 
 ;;; The `documentation-link' Widget.
 ;;
@@ -2934,7 +2949,7 @@ link for that string."
                (widget-create-child-and-convert
                 widget (widget-get widget :visibility-widget)
                 :help-echo "Show or hide rest of the documentation."
-                :on "Hide Rest"
+                :on "Hide"
                 :off "More"
                 :always-active t
                 :action 'widget-parent-action
@@ -3035,35 +3050,13 @@ as the value."
 Completions are taken from the :completion-alist property of the
 widget.  If that isn't a list, it's evalled and expected to yield a list."
   (interactive)
-  (let* ((prefix (buffer-substring-no-properties (widget-field-start widget)
-                                                (point)))
-        (completion-ignore-case (widget-get widget :completion-ignore-case))
+  (let* ((completion-ignore-case (widget-get widget :completion-ignore-case))
         (alist (widget-get widget :completion-alist))
         (_ (unless (listp alist)
-             (setq alist (eval alist))))
-        (completion (try-completion prefix alist)))
-    (cond ((eq completion t)
-          (when completion-ignore-case
-            ;; Replace field with completion in case its case is different.
-            (delete-region (widget-field-start widget)
-                           (widget-field-end widget))
-            (insert-and-inherit (car (assoc-string prefix alist t))))
-          (message "Only match"))
-         ((null completion)
-          (error "No match"))
-         ((not (eq t (compare-strings prefix nil nil completion nil nil
-                                      completion-ignore-case)))
-          (when completion-ignore-case
-            ;; Replace field with completion in case its case is different.
-            (delete-region (widget-field-start widget)
-                           (widget-field-end widget))
-            (insert-and-inherit completion)))
-         (t
-          (message "Making completion list...")
-          (with-output-to-temp-buffer "*Completions*"
-            (display-completion-list
-             (all-completions prefix alist nil)))
-          (message "Making completion list...done")))))
+             (setq alist (eval alist)))))
+    (completion-in-region (widget-field-start widget)
+                          (max (point) (widget-field-text-end widget))
+                          alist)))
 
 (define-widget 'regexp 'string
   "A regular expression."
@@ -3102,29 +3095,9 @@ It reads a file name from an editable text field."
 (defun widget-file-complete ()
   "Perform completion on file name preceding point."
   (interactive)
-  (let* ((end (point))
-        (beg (widget-field-start widget))
-        (pattern (buffer-substring beg end))
-        (name-part (file-name-nondirectory pattern))
-        ;; I think defaulting to root is right
-        ;; because these really should be absolute file names.
-        (directory (or (file-name-directory pattern) "/"))
-        (completion (file-name-completion name-part directory)))
-    (cond ((eq completion t))
-         ((null completion)
-          (message "Can't find completion for \"%s\"" pattern)
-          (ding))
-         ((not (string= name-part completion))
-          (delete-region beg end)
-          (insert (expand-file-name completion directory)))
-         (t
-          (message "Making completion list...")
-          (with-output-to-temp-buffer "*Completions*"
-            (display-completion-list
-             (sort (file-name-all-completions name-part directory)
-                   'string<)
-             name-part))
-          (message "Making completion list...%s" "done")))))
+  (completion-in-region (widget-field-start widget)
+                        (max (point) (widget-field-text-end widget))
+                        'completion-file-name-table))
 
 (defun widget-file-prompt-value (widget prompt value unbound)
   ;; Read file from minibuffer.
@@ -3456,8 +3429,7 @@ To use this type, you must define :match or :match-alternatives."
   :value 0
   :size 1
   :format "%{%t%}: %v\n"
-  ;; `.' does not match newline, but newline is a valid character.
-  :valid-regexp "\\`\\(.\\|\n\\)\\'"
+  :valid-regexp "\\`.\\'"
   :error "This field should contain a single character"
   :value-to-internal (lambda (widget value)
                       (if (stringp value)
@@ -3734,6 +3706,7 @@ example:
 (define-widget 'color 'editable-field
   "Choose a color name (with sample)."
   :format "%{%t%}: %v (%{sample%})\n"
+  :value-create 'widget-color-value-create
   :size 10
   :tag "Color"
   :value "black"
@@ -3742,26 +3715,34 @@ example:
   :notify 'widget-color-notify
   :action 'widget-color-action)
 
+(defun widget-color-value-create (widget)
+  (widget-field-value-create widget)
+  (widget-insert " ")
+  (widget-create-child-and-convert
+   widget 'push-button
+   :tag "Choose" :action 'widget-color--choose-action)
+  (widget-insert " "))
+
+(defun widget-color--choose-action (widget &optional event)
+  (list-colors-display
+   nil nil
+   `(lambda (color)
+      (when (buffer-live-p ,(current-buffer))
+       (widget-value-set ',(widget-get widget :parent) color)
+       (let* ((buf (get-buffer "*Colors*"))
+              (win (get-buffer-window buf 0)))
+         (bury-buffer buf)
+         (and win (> (length (window-list)) 1)
+              (delete-window win)))
+       (pop-to-buffer ,(current-buffer))))))
+
 (defun widget-color-complete (widget)
   "Complete the color in WIDGET."
   (require 'facemenu)                  ; for facemenu-color-alist
-  (let* ((prefix (buffer-substring-no-properties (widget-field-start widget)
-                                                (point)))
-        (list (or facemenu-color-alist
-                  (sort (defined-colors) 'string-lessp)))
-        (completion (try-completion prefix list)))
-    (cond ((eq completion t)
-          (message "Exact match."))
-         ((null completion)
-          (error "Can't find completion for \"%s\"" prefix))
-         ((not (string-equal prefix completion))
-          (insert-and-inherit (substring completion (length prefix))))
-         (t
-          (message "Making completion list...")
-          (with-output-to-temp-buffer "*Completions*"
-            (display-completion-list (all-completions prefix list nil)
-                                     prefix))
-          (message "Making completion list...done")))))
+  (completion-in-region (widget-field-start widget)
+                        (max (point) (widget-field-text-end widget))
+                        (or facemenu-color-alist
+                            (sort (defined-colors) 'string-lessp))))
 
 (defun widget-color-sample-face-get (widget)
   (let* ((value (condition-case nil