summaryrefslogtreecommitdiff
path: root/lisp/wid-edit.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/wid-edit.el')
-rw-r--r--lisp/wid-edit.el145
1 files changed, 116 insertions, 29 deletions
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index a3754236d28..fd08e1c08fa 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -403,10 +403,8 @@ new value.")
;; We want to avoid the face with image buttons.
(unless (widget-get widget :suppress-face)
(overlay-put overlay 'face (widget-apply widget :button-face-get))
- ; Text terminals cannot change mouse pointer shape, so use mouse
- ; face instead.
- (or (display-graphic-p)
- (overlay-put overlay 'mouse-face widget-mouse-face)))
+ (overlay-put overlay 'mouse-face
+ (widget-apply widget :mouse-face-get)))
(overlay-put overlay 'pointer 'hand)
(overlay-put overlay 'follow-link follow-link)
(overlay-put overlay 'help-echo help-echo)))
@@ -664,11 +662,9 @@ button is pressed or inactive, respectively. These are currently ignored."
"Move to where you click, and if it is an active field, invoke it."
(interactive "e")
(mouse-set-point event)
- (if (widget-event-point event)
- (let* ((pos (widget-event-point event))
- (button (get-char-property pos 'button)))
- (if button
- (widget-button-click event)))))
+ (let ((pos (widget-event-point event)))
+ (if (and pos (get-char-property pos 'button))
+ (widget-button-click event))))
;;; Buttons.
@@ -857,6 +853,7 @@ button end points."
(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)] 'widget-backward)
(define-key map [backtab] 'widget-backward)
(define-key map [down-mouse-2] 'widget-button-click)
@@ -1206,22 +1203,24 @@ When not inside a field, move to the previous button or field."
;; or if a special `boundary' field has been added after the widget
;; field.
(if (overlayp overlay)
- (if (and (not (eq (with-current-buffer
- (widget-field-buffer widget)
- (save-restriction
- ;; `widget-narrow-to-field' can be
- ;; active when this function is called
- ;; from an change-functions hook. So
- ;; temporarily remove field narrowing
- ;; before to call `get-char-property'.
- (widen)
- (get-char-property (overlay-end overlay)
- 'field)))
- 'boundary))
- (or widget-field-add-space
- (null (widget-get widget :size))))
- (1- (overlay-end overlay))
- (overlay-end overlay))
+ ;; Don't proceed if overlay has been removed from buffer.
+ (when (overlay-buffer overlay)
+ (if (and (not (eq (with-current-buffer
+ (widget-field-buffer widget)
+ (save-restriction
+ ;; `widget-narrow-to-field' can be
+ ;; active when this function is called
+ ;; from an change-functions hook. So
+ ;; temporarily remove field narrowing
+ ;; before to call `get-char-property'.
+ (widen)
+ (get-char-property (overlay-end overlay)
+ 'field)))
+ 'boundary))
+ (or widget-field-add-space
+ (null (widget-get widget :size))))
+ (1- (overlay-end overlay))
+ (overlay-end overlay)))
(cdr overlay))))
(defun widget-field-find (pos)
@@ -1395,6 +1394,7 @@ The value of the :type attribute should be an unconverted widget type."
:offset 0
:format-handler 'widget-default-format-handler
:button-face-get 'widget-default-button-face-get
+ :mouse-face-get 'widget-default-mouse-face-get
:sample-face-get 'widget-default-sample-face-get
:delete 'widget-default-delete
:copy 'identity
@@ -1539,6 +1539,14 @@ If that does not exists, call the value of `widget-complete-field'."
(widget-apply parent :button-face-get)
widget-button-face))))
+(defun widget-default-mouse-face-get (widget)
+ ;; Use :mouse-face or widget-mouse-face
+ (or (widget-get widget :mouse-face)
+ (let ((parent (widget-get widget :parent)))
+ (if parent
+ (widget-apply parent :mouse-face-get)
+ widget-mouse-face))))
+
(defun widget-default-sample-face-get (widget)
;; Use :sample-face.
(widget-get widget :sample-face))
@@ -2165,7 +2173,8 @@ when he invoked the menu."
(when sibling
(if (widget-value widget)
(widget-apply sibling :activate)
- (widget-apply sibling :deactivate)))))
+ (widget-apply sibling :deactivate))
+ (widget-clear-undo))))
;;; The `checklist' Widget.
@@ -3028,7 +3037,7 @@ widget. If that isn't a list, it's evalled and expected to yield a list."
(define-widget 'file 'string
"A file widget.
-It will read a file name from the minibuffer when invoked."
+It reads a file name from an editable text field."
:complete-function 'widget-file-complete
:prompt-value 'widget-file-prompt-value
:format "%{%t%}: %v"
@@ -3090,7 +3099,7 @@ It will read a file name from the minibuffer when invoked."
;; Fixme: use file-name-as-directory.
(define-widget 'directory 'file
"A directory widget.
-It will read a directory name from the minibuffer when invoked."
+It reads a directory name from an editable text field."
:tag "Directory")
(defvar widget-symbol-prompt-value-history nil
@@ -3198,6 +3207,84 @@ It will read a directory name from the minibuffer when invoked."
(widget-apply widget :notify widget event)
(widget-setup)))
+;;; I'm not sure about what this is good for? KFS.
+(defvar widget-key-sequence-prompt-value-history nil
+ "History of input to `widget-key-sequence-prompt-value'.")
+
+(defvar widget-key-sequence-default-value [ignore]
+ "Default value for an empty key sequence.")
+
+(defvar widget-key-sequence-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map widget-field-keymap)
+ (define-key map [(control ?q)] 'widget-key-sequence-read-event)
+ map))
+
+(define-widget 'key-sequence 'restricted-sexp
+ "A key sequence."
+ :prompt-value 'widget-field-prompt-value
+ :prompt-internal 'widget-symbol-prompt-internal
+; :prompt-match 'fboundp ;; What was this good for? KFS
+ :prompt-history 'widget-key-sequence-prompt-value-history
+ :action 'widget-field-action
+ :match-alternatives '(stringp vectorp)
+ :format "%{%t%}: %v"
+ :validate 'widget-key-sequence-validate
+ :value-to-internal 'widget-key-sequence-value-to-internal
+ :value-to-external 'widget-key-sequence-value-to-external
+ :value widget-key-sequence-default-value
+ :keymap widget-key-sequence-map
+ :help-echo "C-q: insert KEY, EVENT, or CODE; RET: enter value"
+ :tag "Key sequence")
+
+(defun widget-key-sequence-read-event (ev)
+ (interactive (list
+ (let ((inhibit-quit t) quit-flag)
+ (read-event "Insert KEY, EVENT, or CODE: "))))
+ (let ((ev2 (and (memq 'down (event-modifiers ev))
+ (read-event)))
+ (tr (and (keymapp function-key-map)
+ (lookup-key function-key-map (vector ev)))))
+ (when (and (integerp ev)
+ (or (and (<= ?0 ev) (< ev (+ ?0 (min 10 read-quoted-char-radix))))
+ (and (<= ?a (downcase ev))
+ (< (downcase ev) (+ ?a -10 (min 36 read-quoted-char-radix))))))
+ (setq unread-command-events (cons ev unread-command-events)
+ ev (read-quoted-char (format "Enter code (radix %d)" read-quoted-char-radix))
+ tr nil)
+ (if (and (integerp ev) (not (char-valid-p ev)))
+ (insert (char-to-string ev)))) ;; throw invalid char error
+ (setq ev (key-description (list ev)))
+ (when (arrayp tr)
+ (setq tr (key-description (list (aref tr 0))))
+ (if (y-or-n-p (format "Key %s is translated to %s -- use %s? " ev tr tr))
+ (setq ev tr ev2 nil)))
+ (insert (if (= (char-before) ?\s) "" " ") ev " ")
+ (if ev2
+ (insert (key-description (list ev2)) " "))))
+
+(defun widget-key-sequence-validate (widget)
+ (unless (or (stringp (widget-value widget))
+ (vectorp (widget-value widget)))
+ (widget-put widget :error (format "Invalid key sequence: %S"
+ (widget-value widget)))
+ widget))
+
+(defun widget-key-sequence-value-to-internal (widget value)
+ (if (widget-apply widget :match value)
+ (if (equal value widget-key-sequence-default-value)
+ ""
+ (key-description value))
+ value))
+
+(defun widget-key-sequence-value-to-external (widget value)
+ (if (stringp value)
+ (if (string-match "\\`[[:space:]]*\\'" value)
+ widget-key-sequence-default-value
+ (read-kbd-macro value))
+ value))
+
+
(define-widget 'sexp 'editable-field
"An arbitrary Lisp expression."
:tag "Lisp expression"
@@ -3591,7 +3678,7 @@ example:
;; Fixme: match
(define-widget 'color 'editable-field
"Choose a color name (with sample)."
- :format "%t: %v (%{sample%})\n"
+ :format "%{%t%}: %v (%{sample%})\n"
:size 10
:tag "Color"
:value "black"