(eval-when-compile (require 'cl))
;;; Compatibility.
+
+(defun widget-event-point (event)
+ "Character position of the end of event if that exists, or nil."
+ (posn-point (event-end event)))
+
+(defalias 'widget-read-event 'read-event)
(eval-and-compile
(autoload 'pp-to-string "pp")
(autoload 'Info-goto-node "info")
(autoload 'finder-commentary "finder" nil t)
- (when (string-match "XEmacs" emacs-version)
- (condition-case nil
- (require 'overlay)
- (error (load-library "x-overlay"))))
-
- (if (string-match "XEmacs" emacs-version)
- (defun widget-event-point (event)
- "Character position of the end of event if that exists, or nil."
- (if (mouse-event-p event)
- (event-point event)
- nil))
- (defun widget-event-point (event)
- "Character position of the end of event if that exists, or nil."
- (posn-point (event-end event))))
-
- (defalias 'widget-read-event (if (string-match "XEmacs" emacs-version)
- 'next-event
- 'read-event))
-
(unless (and (featurep 'custom) (fboundp 'custom-declare-variable))
;; We have the old custom-library, hack around it!
(defmacro defgroup (&rest args) nil)
(and (eventp event)
(memq (event-basic-type event) '(mouse-1 mouse-2 mouse-3))
(or (memq 'click (event-modifiers event))
- (memq 'drag (event-modifiers event))))))
-
- (unless (fboundp 'functionp)
- ;; Missing from Emacs 19.34 and earlier.
- (defun functionp (object)
- "Non-nil of OBJECT is a type of object that can be called as a function."
- (or (subrp object) (byte-code-function-p object)
- (eq (car-safe object) 'lambda)
- (and (symbolp object) (fboundp object)))))
-
- (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)))))
+ (memq 'drag (event-modifiers event)))))))
;;; Customization.
:group 'widgets
:type 'integer)
-(defcustom widget-menu-minibuffer-flag (string-match "XEmacs" emacs-version)
+(defcustom widget-menu-max-shortcuts 40
+ "Largest number of items for which it works to choose one with a character.
+For a larger number of items, the minibuffer is used."
+ :group 'widgets
+ :type 'integer)
+
+(defcustom widget-menu-minibuffer-flag nil
"*Control how to ask for a choice from the keyboard.
Non-nil means use the minibuffer;
nil means read a single character."
;; We are in Emacs-19, pressed by the mouse
(x-popup-menu event
(list title (cons "" items))))
- ((and (< (length items) widget-menu-max-size)
- event (fboundp 'popup-menu) window-system)
- ;; We are in XEmacs, pressed by the mouse
- (let ((val (get-popup-menu-response
- (cons title
- (mapcar
- (function
- (lambda (x)
- (if (stringp x)
- (vector x nil nil)
- (vector (car x) (list (car x)) t))))
- items)))))
- (setq val (and val
- (listp (event-object val))
- (stringp (car-safe (event-object val)))
- (car (event-object val))))
- (cdr (assoc val items))))
- (widget-menu-minibuffer-flag
+ ((or widget-menu-minibuffer-flag
+ (> (length items) widget-menu-max-shortcuts))
;; Read the choice of name from the minibuffer.
(setq items (widget-remove-if 'stringp items))
(let ((val (completing-read (concat title ": ") items nil t)))
(overlay-put overlay 'keymap map)
(overlay-put overlay 'face face)
(overlay-put overlay 'balloon-help help-echo)
- (overlay-put overlay 'help-echo help-echo)))
+ (overlay-put overlay 'help-echo help-echo))
+ (widget-specify-secret widget))
+
+(defun widget-specify-secret (field)
+ "Replace text in FIELD with value of `:secret', if non-nil."
+ (let ((secret (widget-get field :secret))
+ (size (widget-get field :size)))
+ (when secret
+ (let ((begin (widget-field-start field))
+ (end (widget-field-end field)))
+ (when size
+ (while (and (> end begin)
+ (eq (char-after (1- end)) ?\ ))
+ (setq end (1- end))))
+ (while (< begin end)
+ (let ((old (char-after begin)))
+ (unless (eq old secret)
+ (subst-char-in-region begin (1+ begin) old secret)
+ (put-text-property begin (1+ begin) 'secret old))
+ (setq begin (1+ begin))))))))
(defun widget-specify-button (widget from to)
"Specify button for WIDGET between FROM and TO."
:value-set (widget-apply widget
:value-to-internal value)))
+(defun widget-default-get (widget)
+ "Extract the default value of WIDGET."
+ (or (widget-get widget :value)
+ (widget-apply widget :default-get)))
+
(defun widget-match-inline (widget vals)
;; In WIDGET, match the start of VALS.
(cond ((widget-get widget :inline)
(if (eq extent (event-glyph-extent last))
(set-extent-property extent 'end-glyph down-glyph)
(set-extent-property extent 'end-glyph up-glyph))
- (setq last (next-event event)))
+ (setq last (read-event event)))
;; Release glyph.
(when down-glyph
(set-extent-property extent 'end-glyph up-glyph))
"Go to beginning of field or beginning of line, whichever is first."
(interactive)
(let* ((field (widget-field-find (point)))
- (start (and field (widget-field-start field))))
- (if (and start (not (eq start (point))))
- (goto-char start)
- (call-interactively 'beginning-of-line)))
- ;; XEmacs: preserve the region
- (setq zmacs-region-stays t))
+ (start (and field (widget-field-start field)))
+ (bol (save-excursion
+ (beginning-of-line)
+ (point))))
+ (goto-char (if start
+ (max start bol)
+ bol))))
(defun widget-end-of-line ()
"Go to end of field or end of line, whichever is first."
(interactive)
(let* ((field (widget-field-find (point)))
- (end (and field (widget-field-end field))))
- (if (and end (not (eq end (point))))
- (goto-char end)
- (call-interactively 'end-of-line)))
- ;; XEmacs: preserve the region
- (setq zmacs-region-stays t))
+ (end (and field (widget-field-end field)))
+ (eol (save-excursion
+ (end-of-line)
+ (point))))
+ (goto-char (if end
+ (min end eol)
+ eol))))
(defun widget-kill-line ()
"Kill to end of field or end of line, whichever is first."
(when field
(unless (eq field other)
(debug "Change in different fields"))
- (let ((size (widget-get field :size))
- (secret (widget-get field :secret)))
+ (let ((size (widget-get field :size)))
(when size
(let ((begin (widget-field-start field))
(end (widget-field-end field)))
(while (and (eq (preceding-char) ?\ )
(> (point) begin))
(delete-backward-char 1)))))))
- (when secret
- (let ((begin (widget-field-start field))
- (end (widget-field-end field)))
- (when size
- (while (and (> end begin)
- (eq (char-after (1- end)) ?\ ))
- (setq end (1- end))))
- (while (< begin end)
- (let ((old (char-after begin)))
- (unless (eq old secret)
- (subst-char-in-region begin (1+ begin) old secret)
- (put-text-property begin (1+ begin) 'secret old))
- (setq begin (1+ begin)))))))
+ (widget-specify-secret field))
(widget-apply field :notify field)))
(error (debug "After Change"))))
:delete 'widget-default-delete
:value-set 'widget-default-value-set
:value-inline 'widget-default-value-inline
+ :default-get 'widget-default-default-get
:menu-tag-get 'widget-default-menu-tag-get
:validate (lambda (widget) nil)
:active 'widget-default-active
(widget-value widget)
(list (widget-value widget))))
+(defun widget-default-default-get (widget)
+ ;; Get `:value'.
+ (widget-get widget :value))
+
(defun widget-default-menu-tag-get (widget)
;; Use tag or value for menus.
(or (widget-get widget :menu-tag)
:value-delete 'widget-children-value-delete
:value-get 'widget-choice-value-get
:value-inline 'widget-choice-value-inline
+ :default-get 'widget-choice-default-get
:mouse-down-action 'widget-choice-mouse-down-action
:action 'widget-choice-action
:error "Make a choice"
;; Insert the first choice that matches the value.
(let ((value (widget-get widget :value))
(args (widget-get widget :args))
+ (explicit (widget-get widget :explicit-choice))
+ (explicit-value (widget-get widget :explicit-choice-value))
current)
- (while args
- (setq current (car args)
- args (cdr args))
- (when (widget-apply current :match value)
- (widget-put widget :children (list (widget-create-child-value
- widget current value)))
- (widget-put widget :choice current)
- (setq args nil
- current nil)))
- (when current
- (let ((void (widget-get widget :void)))
- (widget-put widget :children (list (widget-create-child-and-convert
- widget void :value value)))
- (widget-put widget :choice void)))))
+ (if (and explicit (eq value explicit-value))
+ (progn
+ ;; If the user specified the choice for this value,
+ ;; respect that choice as long as the value is the same.
+ (widget-put widget :children (list (widget-create-child-value
+ widget explicit value)))
+ (widget-put widget :choice explicit))
+ (while args
+ (setq current (car args)
+ args (cdr args))
+ (when (widget-apply current :match value)
+ (widget-put widget :children (list (widget-create-child-value
+ widget current value)))
+ (widget-put widget :choice current)
+ (setq args nil
+ current nil)))
+ (when current
+ (let ((void (widget-get widget :void)))
+ (widget-put widget :children (list (widget-create-child-and-convert
+ widget void :value value)))
+ (widget-put widget :choice void))))))
(defun widget-choice-value-get (widget)
;; Get value of the child widget.
;; Get value of the child widget.
(widget-apply (car (widget-get widget :children)) :value-inline))
+(defun widget-choice-default-get (widget)
+ ;; Get default for the first choice.
+ (widget-default-get (car (widget-get widget :args))))
+
(defcustom widget-choice-toggle nil
"If non-nil, a binary choice will just toggle between the values.
Otherwise, the user will explicitly have to choose between the values
(old (widget-get widget :choice))
(tag (widget-apply widget :menu-tag-get))
(completion-ignore-case (widget-get widget :case-fold))
+ this-explicit
current choices)
;; Remember old value.
(if (and old (not (widget-apply widget :validate)))
(cons (cons (widget-apply current :menu-tag-get)
current)
choices)))
+ (setq this-explicit t)
(widget-choose tag (reverse choices) event))))
(when current
- (widget-value-set widget
- (widget-apply current :value-to-external
- (widget-get current :value)))
+ ;; If this was an explicit user choice,
+ ;; record the choice, and the record the value it was made for.
+ ;; widget-choice-value-create will respect this choice,
+ ;; as long as the value is the same.
+ (when this-explicit
+ (widget-put widget :explicit-choice current)
+ (widget-put widget :explicit-choice-value (widget-get widget :value)))
+ (let ((value (widget-default-get current)))
+ (widget-value-set widget
+ (widget-apply current :value-to-external value)))
(widget-setup)
(widget-apply widget :notify widget event)))
(run-hook-with-args 'widget-edit-functions widget))
(if conv
(setq child (widget-create-child-value
widget type value))
- (setq child (widget-create-child widget type))))
+ (setq child (widget-create-child-value
+ widget type
+ (widget-apply type :value-to-external
+ (widget-default-get type))))))
(t
(error "Unknown escape `%c'" escape)))))
(widget-put widget
:value-create 'widget-group-value-create
:value-delete 'widget-children-value-delete
:value-get 'widget-editable-list-value-get
+ :default-get 'widget-group-default-get
:validate 'widget-children-validate
:match 'widget-group-match
:match-inline 'widget-group-match-inline)
children))
(widget-put widget :children (nreverse children))))
+(defun widget-group-default-get (widget)
+ ;; Get the default of the components.
+ (mapcar 'widget-default-get (widget-get widget :args)))
+
(defun widget-group-match (widget values)
;; Match if the components match.
(and (listp values)
:format "%v\n%h"
:documentation-property 'variable-documentation)
+(define-widget 'other 'sexp
+ "Matches any value, but doesn't let the user edit the value.
+This is useful as last item in a `choice' widget.
+You should use this widget type with a default value,
+as in (other DEFAULT) or (other :tag \"NAME\" DEFAULT).
+If the user selects this alternative, that specifies DEFAULT
+as the value."
+ :tag "Other"
+ :format "%t%n"
+ :value 'other)
+
(defvar widget-string-prompt-value-history nil
"History of input to `widget-string-prompt-value'.")
"History of input to `widget-symbol-prompt-value'.")
(define-widget 'symbol 'editable-field
- "A lisp symbol."
+ "A Lisp symbol."
:value nil
:tag "Symbol"
:format "%{%t%}: %v"
"History of input to `widget-function-prompt-value'.")
(define-widget 'function 'sexp
- "A lisp function."
+ "A Lisp function."
:complete-function 'lisp-complete-symbol
:prompt-value 'widget-field-prompt-value
:prompt-internal 'widget-symbol-prompt-internal
(define-widget 'variable 'symbol
;; Should complete on variables.
- "A lisp variable."
+ "A Lisp variable."
:prompt-match 'boundp
:prompt-history 'widget-variable-prompt-value-history
:tag "Variable")
)
(define-widget 'sexp 'editable-field
- "An arbitrary lisp expression."
+ "An arbitrary Lisp expression."
:tag "Lisp expression"
:format "%{%t%}: %v"
:value nil
(integerp value))))
(define-widget 'list 'group
- "A lisp list."
+ "A Lisp list."
:tag "List"
:format "%{%t%}:\n%v")
(define-widget 'vector 'group
- "A lisp vector."
+ "A Lisp vector."
:tag "Vector"
:format "%{%t%}:\n%v"
:match 'widget-vector-match
(widget-value widget)
(error (widget-get widget :value))))
(symbol (intern (concat "fg:" value))))
- (if (string-match "XEmacs" emacs-version)
- (prog1 symbol
- (or (find-face symbol)
- (set-face-foreground (make-face symbol) value)))
- (condition-case nil
- (facemenu-get-face symbol)
- (error 'default)))))
+ (condition-case nil
+ (facemenu-get-face symbol)
+ (error 'default))))
(defvar widget-color-choice-list nil)
;; Variable holding the possible colors.
(defun widget-color-choice-list ()
(unless widget-color-choice-list
(setq widget-color-choice-list
- (if (fboundp 'read-color-completion-table)
- (read-color-completion-table)
- (mapcar '(lambda (color) (list color))
- (x-defined-colors)))))
+ (mapcar '(lambda (color) (list color))
+ (x-defined-colors))))
widget-color-choice-list)
(defvar widget-color-history nil
(select-window win)
(let* ((result (compute-motion (window-start win)
'(0 . 0)
- (window-end win)
+ (point-max)
where
(window-width win)
(cons (window-hscroll) 0)