]> code.delx.au - gnu-emacs/blobdiff - lisp/wid-edit.el
Merge from emacs-23
[gnu-emacs] / lisp / wid-edit.el
index e75aba222690d51fa4129f54d1aec22b501a9395..9c7de61d7cdc39bd80792755a2bcf39d838a0d9a 100644 (file)
@@ -6,6 +6,7 @@
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Maintainer: FSF
 ;; Keywords: extensions
+;; Package: emacs
 
 ;; This file is part of GNU Emacs.
 
@@ -56,8 +57,6 @@
 
 ;;; Code:
 
-(defvar widget)
-
 ;;; Compatibility.
 
 (defun widget-event-point (event)
@@ -78,8 +77,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."
@@ -254,7 +252,9 @@ minibuffer."
               ;; Allocate digits to disabled alternatives
               ;; so that the digit of a given alternative never varies.
               (setq next-digit (1+ next-digit)))
-            (insert "\nC-g = Quit"))
+            (insert "\nC-g = Quit")
+            (goto-char (point-min))
+            (forward-line))
           (or some-choice-enabled
               (error "None of the choices is currently meaningful"))
           (define-key map [?\C-g] 'keyboard-quit)
@@ -637,9 +637,9 @@ extension (xpm, xbm, gif, jpg, or png) located in
                specs)
           (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)))
+              (push (list :type (car elt) :file (concat image ext)
+                          :ascent 'center) specs)))
+          (find-image (nreverse specs))))
        (t
         ;; Oh well.
         nil)))
@@ -656,7 +656,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))
@@ -1336,7 +1336,7 @@ Unlike (get-char-property POS 'field), this works with empty fields too."
                     (goto-char end)
                     (while (and (eq (preceding-char) ?\s)
                                 (> (point) begin))
-                      (delete-backward-char 1)))))))
+                      (delete-char -1)))))))
        (widget-specify-secret field))
       (widget-apply field :notify field))))
 
@@ -1460,11 +1460,15 @@ The value of the :type attribute should be an unconverted widget type."
   :notify 'widget-default-notify
   :prompt-value 'widget-default-prompt-value)
 
+(defvar widget--completing-widget)
+
 (defun widget-default-complete (widget)
   "Call the value of the :complete-function property of WIDGET.
-If that does not exist, call the value of `widget-complete-field'."
-  (call-interactively (or (widget-get widget :complete-function)
-                         widget-complete-field)))
+If that does not exist, call the value of `widget-complete-field'.
+During this call, `widget--completing-widget' is bound to WIDGET."
+  (let ((widget--completing-widget widget))
+    (call-interactively (or (widget-get widget :complete-function)
+                           widget-complete-field))))
 
 (defun widget-default-create (widget)
   "Create WIDGET at point in the current buffer."
@@ -1479,7 +1483,7 @@ If that does not exist, call the value of `widget-complete-field'."
      ;; Parse escapes in format.
      (while (re-search-forward "%\\(.\\)" nil t)
        (let ((escape (char-after (match-beginning 1))))
-        (delete-backward-char 2)
+        (delete-char -2)
         (cond ((eq escape ?%)
                (insert ?%))
               ((eq escape ?\[)
@@ -1512,7 +1516,7 @@ If that does not exist, call the value of `widget-complete-field'."
                    (setq doc-begin (point))
                    (insert doc)
                    (while (eq (preceding-char) ?\n)
-                     (delete-backward-char 1))
+                     (delete-char -1))
                    (insert ?\n)
                    (setq doc-end (point)))))
               ((eq escape ?h)
@@ -1876,6 +1880,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)
@@ -1914,6 +1919,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))
@@ -1951,7 +1968,6 @@ the earlier input."
   (let ((from (widget-field-start 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)
@@ -2179,19 +2195,9 @@ when he invoked the menu."
   ;; We could probably do the same job as the images using single
   ;; space characters in a boxed face with a stretch specification to
   ;; make them square.
-  :on-glyph '(create-image "\300\300\141\143\067\076\034\030"
-                          'xbm t :width 8 :height 8
-                          :background "grey75" ; like default mode line
-                          :foreground "black"
-                          :relief -2
-                          :ascent 'center)
+  :on-glyph "checked"
   :off "[ ]"
-  :off-glyph '(create-image (make-string 8 0)
-                           'xbm t :width 8 :height 8
-                           :background "grey75"
-                           :foreground "black"
-                           :relief -2
-                           :ascent 'center)
+  :off-glyph "unchecked"
   :help-echo "Toggle this item."
   :action 'widget-checkbox-action)
 
@@ -2223,11 +2229,10 @@ when he invoked the menu."
 
 (defun widget-checklist-value-create (widget)
   ;; Insert all values
-  (let ((alist (widget-checklist-match-find widget (widget-get widget :value)))
-       (args (widget-get widget :args)))
-    (while args
-      (widget-checklist-add-item widget (car args) (assq (car args) alist))
-      (setq args (cdr args)))
+  (let ((alist (widget-checklist-match-find widget))
+       (args  (widget-get widget :args)))
+    (dolist (item args)
+      (widget-checklist-add-item widget item (assq item alist)))
     (widget-put widget :children (nreverse (widget-get widget :children)))))
 
 (defun widget-checklist-add-item (widget type chosen)
@@ -2248,7 +2253,7 @@ If the item is checked, CHOSEN is a cons whose cdr is the value."
      ;; Parse % escapes in format.
      (while (re-search-forward "%\\([bv%]\\)" nil t)
        (let ((escape (char-after (match-beginning 1))))
-        (delete-backward-char 2)
+        (delete-char -2)
         (cond ((eq escape ?%)
                (insert ?%))
               ((eq escape ?b)
@@ -2300,9 +2305,10 @@ If the item is checked, CHOSEN is a cons whose cdr is the value."
                     values nil)))))
     (cons found rest)))
 
-(defun widget-checklist-match-find (widget vals)
+(defun widget-checklist-match-find (widget &optional vals)
   "Find the vals which match a type in the checklist.
 Return an alist of (TYPE MATCH)."
+  (or vals (setq vals (widget-get widget :value)))
   (let ((greedy (widget-get widget :greedy))
        (args (copy-sequence (widget-get widget :args)))
        found)
@@ -2431,7 +2437,7 @@ Return an alist of (TYPE MATCH)."
      ;; Parse % escapes in format.
      (while (re-search-forward "%\\([bv%]\\)" nil t)
        (let ((escape (char-after (match-beginning 1))))
-        (delete-backward-char 2)
+        (delete-char -2)
         (cond ((eq escape ?%)
                (insert ?%))
               ((eq escape ?b)
@@ -2710,7 +2716,7 @@ Return an alist of (TYPE MATCH)."
      ;; Parse % escapes in format.
      (while (re-search-forward "%\\(.\\)" nil t)
        (let ((escape (char-after (match-beginning 1))))
-        (delete-backward-char 2)
+        (delete-char -2)
         (cond ((eq escape ?%)
                (insert ?%))
               ((eq escape ?i)
@@ -2795,11 +2801,10 @@ Return an alist of (TYPE MATCH)."
        argument answer found)
     (while args
       (setq argument (car args)
-           args (cdr args)
-           answer (widget-match-inline argument vals))
-      (if answer
-         (setq vals (cdr answer)
-               found (append found (car answer)))
+           args     (cdr args))
+      (if (setq answer (widget-match-inline argument vals))
+         (setq found (append found (car answer))
+               vals (cdr answer))
        (setq vals nil
              args nil)))
     (if answer
@@ -2808,11 +2813,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
@@ -2820,21 +2833,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.
 ;;
@@ -2937,7 +2946,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
@@ -3031,14 +3040,13 @@ as the value."
   :complete-function 'ispell-complete-word
   :prompt-history 'widget-string-prompt-value-history)
 
-(defvar widget)
-
 (defun widget-string-complete ()
   "Complete contents of string field.
 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* ((completion-ignore-case (widget-get widget :completion-ignore-case))
+  (let* ((widget widget--completing-widget)
+        (completion-ignore-case (widget-get widget :completion-ignore-case))
         (alist (widget-get widget :completion-alist))
         (_ (unless (listp alist)
              (setq alist (eval alist)))))
@@ -3083,9 +3091,10 @@ It reads a file name from an editable text field."
 (defun widget-file-complete ()
   "Perform completion on file name preceding point."
   (interactive)
-  (completion-in-region (widget-field-start widget)
-                        (max (point) (widget-field-text-end widget))
-                        'completion-file-name-table))
+  (let ((widget widget--completing-widget))
+    (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.
@@ -3694,6 +3703,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"
@@ -3702,6 +3712,27 @@ 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