Don't call turn_on_atimers around `connect' (Bug#5723).
[bpt/emacs.git] / lisp / wid-edit.el
index 5a22b37..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."
@@ -639,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)))
@@ -657,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))
@@ -875,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.")
@@ -1160,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.
 
@@ -1257,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."
@@ -1862,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)
@@ -1900,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))
@@ -1935,19 +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))
-                     (> to from)
-                     (eq (char-after (1- to)) ?\s))
-           (setq to (1- to)))
          (let ((result (buffer-substring-no-properties from to)))
            (when secret
              (let ((index 0))
@@ -2799,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
@@ -2811,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.
 ;;
@@ -2928,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
@@ -3029,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."
@@ -3096,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.
@@ -3727,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"
@@ -3735,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