Mercurial > hg > xemacs-beta
comparison lisp/custom/wid-edit.el @ 195:a2f645c6b9f8 r20-3b24
Import from CVS: tag r20-3b24
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:59:05 +0200 |
parents | f53b5ca2e663 |
children | acd284d43ca1 |
comparison
equal
deleted
inserted
replaced
194:2947057885e5 | 195:a2f645c6b9f8 |
---|---|
1 ;;; wid-edit.el --- Functions for creating and using widgets. | 1 ;;; wid-edit.el --- Functions for creating and using widgets. |
2 ;; | 2 ;; |
3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
4 ;; | 4 ;; |
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> | 5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk> |
6 ;; Maintainer: Hrvoje Niksic <hniksic@srce.hr> | |
6 ;; Keywords: extensions | 7 ;; Keywords: extensions |
7 ;; Version: 1.9960 | 8 ;; Version: 1.9960-x |
8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ | 9 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ |
9 | 10 |
10 ;; This file is part of GNU Emacs. | 11 ;; This file is part of XEmacs. |
11 | 12 |
12 ;; GNU Emacs is free software; you can redistribute it and/or modify | 13 ;; XEmacs is free software; you can redistribute it and/or modify |
13 ;; it under the terms of the GNU General Public License as published by | 14 ;; it under the terms of the GNU General Public License as published by |
14 ;; the Free Software Foundation; either version 2, or (at your option) | 15 ;; the Free Software Foundation; either version 2, or (at your option) |
15 ;; any later version. | 16 ;; any later version. |
16 | 17 |
17 ;; GNU Emacs is distributed in the hope that it will be useful, | 18 ;; XEmacs is distributed in the hope that it will be useful, |
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | 19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 ;; GNU General Public License for more details. | 21 ;; GNU General Public License for more details. |
21 | 22 |
22 ;; You should have received a copy of the GNU General Public License | 23 ;; You should have received a copy of the GNU General Public License |
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the | 24 ;; along with XEmacs; see the file COPYING. If not, write to the |
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
25 ;; Boston, MA 02111-1307, USA. | 26 ;; Boston, MA 02111-1307, USA. |
26 | 27 |
27 ;;; Commentary: | 28 ;;; Commentary: |
28 ;; | 29 ;; |
29 ;; See `widget.el'. | 30 ;; See `widget.el'. |
30 | 31 |
32 | |
31 ;;; Code: | 33 ;;; Code: |
32 | 34 |
33 (require 'widget) | 35 (require 'widget) |
34 (eval-when-compile (require 'cl)) | 36 |
35 | 37 (autoload 'pp-to-string "pp") |
36 ;;; Compatibility. | 38 (autoload 'finder-commentary "finder" nil t) |
37 | 39 |
38 (eval-and-compile | 40 (defun widget-event-point (event) |
39 (autoload 'pp-to-string "pp") | 41 "Character position of the end of event if that exists, or nil." |
40 (autoload 'Info-goto-node "info") | 42 (if (mouse-event-p event) |
41 (autoload 'finder-commentary "finder" nil t) | 43 (event-point event) |
42 | 44 nil)) |
43 (when (string-match "XEmacs" emacs-version) | |
44 (condition-case nil | |
45 (require 'overlay) | |
46 (error (load-library "x-overlay")))) | |
47 | |
48 (if (string-match "XEmacs" emacs-version) | |
49 (defun widget-event-point (event) | |
50 "Character position of the end of event if that exists, or nil." | |
51 (if (mouse-event-p event) | |
52 (event-point event) | |
53 nil)) | |
54 (defun widget-event-point (event) | |
55 "Character position of the end of event if that exists, or nil." | |
56 (posn-point (event-end event)))) | |
57 | |
58 (defalias 'widget-read-event (if (string-match "XEmacs" emacs-version) | |
59 'next-event | |
60 'read-event)) | |
61 | |
62 ;; The following should go away when bundled with Emacs. | |
63 (condition-case () | |
64 (require 'custom) | |
65 (error nil)) | |
66 | |
67 (unless (and (featurep 'custom) (fboundp 'custom-declare-variable)) | |
68 ;; We have the old custom-library, hack around it! | |
69 (defmacro defgroup (&rest args) nil) | |
70 (defmacro defcustom (var value doc &rest args) | |
71 (` (defvar (, var) (, value) (, doc)))) | |
72 (defmacro defface (&rest args) nil) | |
73 (define-widget-keywords :prefix :tag :load :link :options :type :group) | |
74 (when (fboundp 'copy-face) | |
75 (copy-face 'default 'widget-documentation-face) | |
76 (copy-face 'bold 'widget-button-face) | |
77 (copy-face 'italic 'widget-field-face))) | |
78 | |
79 (unless (fboundp 'button-release-event-p) | |
80 ;; XEmacs function missing from Emacs. | |
81 (defun button-release-event-p (event) | |
82 "Non-nil if EVENT is a mouse-button-release event object." | |
83 (and (eventp event) | |
84 (memq (event-basic-type event) '(mouse-1 mouse-2 mouse-3)) | |
85 (or (memq 'click (event-modifiers event)) | |
86 (memq 'drag (event-modifiers event)))))) | |
87 | |
88 (unless (fboundp 'functionp) | |
89 ;; Missing from Emacs 19.34 and earlier. | |
90 (defun functionp (object) | |
91 "Non-nil of OBJECT is a type of object that can be called as a function." | |
92 (or (subrp object) (byte-code-function-p object) | |
93 (eq (car-safe object) 'lambda) | |
94 (and (symbolp object) (fboundp object))))) | |
95 | |
96 (unless (fboundp 'error-message-string) | |
97 ;; Emacs function missing in XEmacs. | |
98 (defun error-message-string (obj) | |
99 "Convert an error value to an error message." | |
100 (let ((buf (get-buffer-create " *error-message*"))) | |
101 (erase-buffer buf) | |
102 (display-error obj buf) | |
103 (buffer-string buf))))) | |
104 | 45 |
105 ;;; Customization. | 46 ;;; Customization. |
106 | 47 |
107 (defgroup widgets nil | 48 (defgroup widgets nil |
108 "Customization support for the Widget Library." | 49 "Customization support for the Widget Library." |
160 (t | 101 (t |
161 (:italic t))) | 102 (:italic t))) |
162 "Face used for editable fields." | 103 "Face used for editable fields." |
163 :group 'widget-faces) | 104 :group 'widget-faces) |
164 | 105 |
165 (defface widget-single-line-field-face '((((class grayscale color) | 106 ;; Currently unused |
166 (background light)) | 107 ;(defface widget-single-line-field-face '((((class grayscale color) |
167 (:background "gray85")) | 108 ; (background light)) |
168 (((class grayscale color) | 109 ; (:background "gray85")) |
169 (background dark)) | 110 ; (((class grayscale color) |
170 (:background "dim gray")) | 111 ; (background dark)) |
171 (t | 112 ; (:background "dim gray")) |
172 (:italic t))) | 113 ; (t |
173 "Face used for editable fields spanning only a single line." | 114 ; (:italic t))) |
174 :group 'widget-faces) | 115 ; "Face used for editable fields spanning only a single line." |
175 | 116 ; :group 'widget-faces) |
176 (defvar widget-single-line-display-table | 117 ; |
177 (let ((table (make-display-table))) | 118 ;(defvar widget-single-line-display-table |
178 (aset table 9 "^I") | 119 ; (let ((table (make-display-table))) |
179 (aset table 10 "^J") | 120 ; (aset table 9 "^I") |
180 table) | 121 ; (aset table 10 "^J") |
181 "Display table used for single-line editable fields.") | 122 ; table) |
182 | 123 ; "Display table used for single-line editable fields.") |
183 (when (fboundp 'set-face-display-table) | 124 ; |
184 (set-face-display-table 'widget-single-line-field-face | 125 ;(set-face-display-table 'widget-single-line-field-face |
185 widget-single-line-display-table)) | 126 ; widget-single-line-display-table) |
186 | 127 |
128 | |
129 ;; Some functions from this file have been ported to C for speed. | |
130 ;; Setting this to t (*before* loading wid-edit.el) will make them | |
131 ;; shadow the subrs. It should be used only for debugging purposes. | |
132 (defvar widget-shadow-subrs nil) | |
133 | |
134 | |
187 ;;; Utility functions. | 135 ;;; Utility functions. |
188 ;; | 136 ;; |
189 ;; These are not really widget specific. | 137 ;; These are not really widget specific. |
190 | 138 |
191 (defsubst widget-plist-member (plist prop) | 139 (when (or (not (fboundp 'widget-plist-member)) |
192 ;; Return non-nil if PLIST has the property PROP. | 140 widget-shadow-subrs) |
193 ;; PLIST is a property list, which is a list of the form | 141 ;; Recoded in C, for efficiency. It used to be a defsubst, but old |
194 ;; (PROP1 VALUE1 PROP2 VALUE2 ...). PROP is a symbol. | 142 ;; compiled code won't fail -- it will just be slower. |
195 ;; Unlike `plist-get', this allows you to distinguish between a missing | 143 (defun widget-plist-member (plist prop) |
196 ;; property and a property with the value nil. | 144 ;; Return non-nil if PLIST has the property PROP. |
197 ;; The value is actually the tail of PLIST whose car is PROP. | 145 ;; PLIST is a property list, which is a list of the form |
198 (while (and plist (not (eq (car plist) prop))) | 146 ;; (PROP1 VALUE1 PROP2 VALUE2 ...). PROP is a symbol. |
199 (setq plist (cdr (cdr plist)))) | 147 ;; Unlike `plist-get', this allows you to distinguish between a missing |
200 plist) | 148 ;; property and a property with the value nil. |
149 ;; The value is actually the tail of PLIST whose car is PROP. | |
150 (while (and plist (not (eq (car plist) prop))) | |
151 (setq plist (cddr plist))) | |
152 plist)) | |
201 | 153 |
202 (defun widget-princ-to-string (object) | 154 (defun widget-princ-to-string (object) |
203 ;; Return string representation of OBJECT, any Lisp object. | 155 ;; Return string representation of OBJECT, any Lisp object. |
204 ;; No quoting characters are used; no delimiters are printed around | 156 ;; No quoting characters are used; no delimiters are printed around |
205 ;; the contents of strings. | 157 ;; the contents of strings. |
206 (save-excursion | 158 (with-current-buffer (get-buffer-create " *widget-tmp*") |
207 (set-buffer (get-buffer-create " *widget-tmp*")) | |
208 (erase-buffer) | 159 (erase-buffer) |
209 (let ((standard-output (current-buffer))) | 160 (princ object (current-buffer)) |
210 (princ object)) | |
211 (buffer-string))) | 161 (buffer-string))) |
212 | 162 |
213 (defun widget-clear-undo () | 163 (defun widget-clear-undo () |
214 "Clear all undo information." | 164 "Clear all undo information." |
215 (buffer-disable-undo (current-buffer)) | 165 (buffer-disable-undo) |
216 (buffer-enable-undo)) | 166 (buffer-enable-undo)) |
217 | 167 |
218 (defcustom widget-menu-max-size 40 | 168 (defcustom widget-menu-max-size 40 |
219 "Largest number of items allowed in a popup-menu. | 169 "Largest number of items allowed in a popup-menu. |
220 Larger menus are read through the minibuffer." | 170 Larger menus are read through the minibuffer." |
221 :group 'widgets | 171 :group 'widgets |
222 :type 'integer) | 172 :type 'integer) |
223 | 173 |
224 (defcustom widget-menu-minibuffer-flag (string-match "XEmacs" emacs-version) | 174 (defcustom widget-menu-minibuffer-flag nil |
225 "*Control how to ask for a choice from the keyboard. | 175 "*Control how to ask for a choice from the keyboard. |
226 Non-nil means use the minibuffer; | 176 Non-nil means use the minibuffer; |
227 nil means read a single character." | 177 nil means read a single character." |
228 :group 'widgets | 178 :group 'widgets |
229 :type 'boolean) | 179 :type 'boolean) |
240 The user is asked to choose between each NAME from the items alist, | 190 The user is asked to choose between each NAME from the items alist, |
241 and the VALUE of the chosen element will be returned. If EVENT is a | 191 and the VALUE of the chosen element will be returned. If EVENT is a |
242 mouse event, and the number of elements in items is less than | 192 mouse event, and the number of elements in items is less than |
243 `widget-menu-max-size', a popup menu will be used, otherwise the | 193 `widget-menu-max-size', a popup menu will be used, otherwise the |
244 minibuffer." | 194 minibuffer." |
245 (cond ((and (< (length items) widget-menu-max-size) | 195 (cond ((and (< (length items) widget-menu-max-size) |
246 event (fboundp 'x-popup-menu) window-system) | 196 event |
247 ;; We are in Emacs-19, pressed by the mouse | 197 (console-on-window-system-p)) |
248 (x-popup-menu event | 198 ;; Pressed by the mouse. |
249 (list title (cons "" items)))) | |
250 ((and (< (length items) widget-menu-max-size) | |
251 event (fboundp 'popup-menu) window-system) | |
252 ;; We are in XEmacs, pressed by the mouse | |
253 (let ((val (get-popup-menu-response | 199 (let ((val (get-popup-menu-response |
254 (cons title | 200 (cons title |
255 (mapcar | 201 (mapcar (lambda (x) |
256 (function | 202 (if (stringp x) |
257 (lambda (x) | 203 (vector x nil nil) |
258 (if (stringp x) | 204 (vector (car x) (list (car x)) t))) |
259 (vector x nil nil) | 205 items))))) |
260 (vector (car x) (list (car x)) t)))) | |
261 items))))) | |
262 (setq val (and val | 206 (setq val (and val |
263 (listp (event-object val)) | 207 (listp (event-object val)) |
264 (stringp (car-safe (event-object val))) | 208 (stringp (car-safe (event-object val))) |
265 (car (event-object val)))) | 209 (car (event-object val)))) |
266 (cdr (assoc val items)))) | 210 (cdr (assoc val items)))) |
267 (widget-menu-minibuffer-flag | 211 ((and (not widget-menu-minibuffer-flag) |
268 ;; Read the choice of name from the minibuffer. | 212 ;; Can't handle more than 10 items (as many digits) |
269 (setq items (widget-remove-if 'stringp items)) | 213 (<= (length items) 10)) |
270 (let ((val (completing-read (concat title ": ") items nil t))) | |
271 (if (stringp val) | |
272 (let ((try (try-completion val items))) | |
273 (when (stringp try) | |
274 (setq val try)) | |
275 (cdr (assoc val items))) | |
276 nil))) | |
277 (t | |
278 ;; Construct a menu of the choices | 214 ;; Construct a menu of the choices |
279 ;; and then use it for prompting for a single character. | 215 ;; and then use it for prompting for a single character. |
280 (let* ((overriding-terminal-local-map | 216 (let* ((overriding-terminal-local-map (make-sparse-keymap)) |
281 (make-sparse-keymap)) | 217 (map (make-sparse-keymap title)) |
282 map choice (next-digit ?0) | 218 (next-digit ?0) |
283 some-choice-enabled | 219 some-choice-enabled value) |
284 value) | |
285 ;; Define SPC as a prefix char to get to this menu. | 220 ;; Define SPC as a prefix char to get to this menu. |
286 (define-key overriding-terminal-local-map " " | 221 (define-key overriding-terminal-local-map " " map) |
287 (setq map (make-sparse-keymap title))) | 222 (with-current-buffer (get-buffer-create " widget-choose") |
288 (save-excursion | |
289 (set-buffer (get-buffer-create " widget-choose")) | |
290 (erase-buffer) | 223 (erase-buffer) |
291 (insert "Available choices:\n\n") | 224 (insert "Available choices:\n\n") |
292 (while items | 225 (dolist (choice items) |
293 (setq choice (car items) items (cdr items)) | 226 (when (consp choice) |
294 (if (consp choice) | 227 (let* ((name (car choice)) |
295 (let* ((name (car choice)) | 228 (function (cdr choice))) |
296 (function (cdr choice))) | 229 (insert (format "%c = %s\n" next-digit name)) |
297 (insert (format "%c = %s\n" next-digit name)) | 230 (define-key map (vector next-digit) function) |
298 (define-key map (vector next-digit) function) | 231 (setq some-choice-enabled t))) |
299 (setq some-choice-enabled t))) | |
300 ;; Allocate digits to disabled alternatives | 232 ;; Allocate digits to disabled alternatives |
301 ;; so that the digit of a given alternative never varies. | 233 ;; so that the digit of a given alternative never varies. |
302 (setq next-digit (1+ next-digit))) | 234 (incf next-digit)) |
303 (insert "\nC-g = Quit")) | 235 (insert "\nC-g = Quit")) |
304 (or some-choice-enabled | 236 (or some-choice-enabled |
305 (error "None of the choices is currently meaningful")) | 237 (error "None of the choices is currently meaningful")) |
306 (define-key map [?\C-g] 'keyboard-quit) | 238 (define-key map [?\C-g] 'keyboard-quit) |
307 (define-key map [t] 'keyboard-quit) | 239 (define-key map [t] 'keyboard-quit) |
308 (setcdr map (nreverse (cdr map))) | 240 ;(setcdr map (nreverse (cdr map))) |
309 ;; Unread a SPC to lead to our new menu. | 241 ;; Unread a SPC to lead to our new menu. |
310 (setq unread-command-events (cons ?\ unread-command-events)) | 242 (push (character-to-event ?\ ) unread-command-events) |
311 ;; Read a char with the menu, and return the result | 243 ;; Read a char with the menu, and return the result |
312 ;; that corresponds to it. | 244 ;; that corresponds to it. |
313 (save-window-excursion | 245 (save-window-excursion |
314 (display-buffer (get-buffer " widget-choose")) | 246 (display-buffer (get-buffer " widget-choose")) |
315 (let ((cursor-in-echo-area t)) | 247 (let ((cursor-in-echo-area t)) |
316 (setq value | 248 (setq value |
317 (lookup-key overriding-terminal-local-map | 249 (lookup-key overriding-terminal-local-map |
318 (read-key-sequence title) t)))) | 250 (read-key-sequence (concat title ": ") t))))) |
251 (message "") | |
319 (when (eq value 'keyboard-quit) | 252 (when (eq value 'keyboard-quit) |
320 (error "Canceled")) | 253 (error "Canceled")) |
321 value)))) | 254 value)) |
322 | 255 (t |
323 (defun widget-remove-if (predictate list) | 256 ;; Read the choice of name from the minibuffer. |
324 (let (result (tail list)) | 257 (setq items (remove-if 'stringp items)) |
325 (while tail | 258 (let ((val (completing-read (concat title ": ") items nil t))) |
326 (or (funcall predictate (car tail)) | 259 (if (stringp val) |
327 (setq result (cons (car tail) result))) | 260 (let ((try (try-completion val items))) |
328 (setq tail (cdr tail))) | 261 (when (stringp try) |
329 (nreverse result))) | 262 (setq val try)) |
330 | 263 (cdr (assoc val items))) |
264 nil))))) | |
265 | |
266 | |
331 ;;; Widget text specifications. | 267 ;;; Widget text specifications. |
332 ;; | 268 ;; |
333 ;; These functions are for specifying text properties. | 269 ;; These functions are for specifying text properties. |
334 | 270 |
335 (defcustom widget-field-add-space | 271 (defcustom widget-field-add-space t |
336 (or t | 272 ;; Setting this to nil might be available, once some problems are resolved. |
337 ;; It shouldn't be necessary in 20.3, but I need to debug it first. | |
338 (< emacs-major-version 20) | |
339 (and (eq emacs-major-version 20) | |
340 (< emacs-minor-version 3)) | |
341 (not (string-match "XEmacs" emacs-version))) | |
342 "Non-nil means add extra space at the end of editable text fields. | 273 "Non-nil means add extra space at the end of editable text fields. |
343 | 274 |
344 This is needed on all versions of Emacs, and on XEmacs before 20.3. | 275 This is needed on all versions of Emacs. If you don't add the space, |
345 If you don't add the space, it will become impossible to edit a zero | 276 it will become impossible to edit a zero size field." |
346 size field." | |
347 :type 'boolean | 277 :type 'boolean |
348 :group 'widgets) | 278 :group 'widgets) |
349 | 279 |
350 (defcustom widget-field-use-before-change | 280 (defcustom widget-field-use-before-change |
351 (and (or (> emacs-minor-version 34) | 281 (and (or (> emacs-minor-version 34) |
364 (goto-char to) | 294 (goto-char to) |
365 (cond ((null (widget-get widget :size)) | 295 (cond ((null (widget-get widget :size)) |
366 (forward-char 1)) | 296 (forward-char 1)) |
367 ;; Terminating space is not part of the field, but necessary in | 297 ;; Terminating space is not part of the field, but necessary in |
368 ;; order for local-map to work. Remove next sexp if local-map works | 298 ;; order for local-map to work. Remove next sexp if local-map works |
369 ;; at the end of the overlay. | 299 ;; at the end of the extent. |
370 (widget-field-add-space | 300 (widget-field-add-space |
371 (insert-and-inherit " "))) | 301 (insert-and-inherit " "))) |
372 (setq to (point))) | 302 (setq to (point))) |
373 (let ((map (widget-get widget :keymap)) | 303 (let ((map (widget-get widget :keymap)) |
374 (face (or (widget-get widget :value-face) 'widget-field-face)) | 304 (face (or (widget-get widget :value-face) 'widget-field-face)) |
375 (help-echo (widget-get widget :help-echo)) | 305 (help-echo (widget-get widget :help-echo)) |
376 (overlay (make-overlay from to nil | 306 (extent (make-extent from to))) |
377 nil (or (not widget-field-add-space) | |
378 (widget-get widget :size))))) | |
379 (unless (or (stringp help-echo) (null help-echo)) | 307 (unless (or (stringp help-echo) (null help-echo)) |
380 (setq help-echo 'widget-mouse-help)) | 308 (setq help-echo 'widget-mouse-help)) |
381 (widget-put widget :field-overlay overlay) | 309 (widget-put widget :field-extent extent) |
382 (overlay-put overlay 'detachable nil) | 310 (and (or (not widget-field-add-space) |
383 (overlay-put overlay 'field widget) | 311 (widget-get widget :size)) |
384 (overlay-put overlay 'local-map map) | 312 (set-extent-property extent 'end-closed t)) |
385 (overlay-put overlay 'keymap map) | 313 (set-extent-property extent 'detachable nil) |
386 (overlay-put overlay 'face face) | 314 (set-extent-property extent 'field widget) |
387 (overlay-put overlay 'balloon-help help-echo) | 315 (set-extent-property extent 'keymap map) |
388 (overlay-put overlay 'help-echo help-echo))) | 316 (set-extent-property extent 'face face) |
317 (set-extent-property extent 'balloon-help help-echo) | |
318 (set-extent-property extent 'help-echo help-echo))) | |
389 | 319 |
390 (defun widget-specify-button (widget from to) | 320 (defun widget-specify-button (widget from to) |
391 "Specify button for WIDGET between FROM and TO." | 321 "Specify button for WIDGET between FROM and TO." |
392 (let ((face (widget-apply widget :button-face-get)) | 322 (let ((face (widget-apply widget :button-face-get)) |
393 (help-echo (widget-get widget :help-echo)) | 323 (help-echo (widget-get widget :help-echo)) |
394 (overlay (make-overlay from to nil t nil))) | 324 (extent (make-extent from to))) |
395 (widget-put widget :button-overlay overlay) | 325 (widget-put widget :button-extent extent) |
396 (unless (or (null help-echo) (stringp help-echo)) | 326 (unless (or (null help-echo) (stringp help-echo)) |
397 (setq help-echo 'widget-mouse-help)) | 327 (setq help-echo 'widget-mouse-help)) |
398 (overlay-put overlay 'button widget) | 328 (set-extent-property extent 'start-open t) |
399 (overlay-put overlay 'mouse-face widget-mouse-face) | 329 (set-extent-property extent 'button widget) |
400 (overlay-put overlay 'balloon-help help-echo) | 330 (set-extent-property extent 'mouse-face widget-mouse-face) |
401 (overlay-put overlay 'help-echo help-echo) | 331 (set-extent-property extent 'balloon-help help-echo) |
402 (overlay-put overlay 'face face))) | 332 (set-extent-property extent 'help-echo help-echo) |
333 (set-extent-property extent 'face face))) | |
403 | 334 |
404 (defun widget-mouse-help (extent) | 335 (defun widget-mouse-help (extent) |
405 "Find mouse help string for button in extent." | 336 "Find mouse help string for button in extent." |
406 (let* ((widget (widget-at (extent-start-position extent))) | 337 (let* ((widget (widget-at (extent-start-position extent))) |
407 (help-echo (and widget (widget-get widget :help-echo)))) | 338 (help-echo (and widget (widget-get widget :help-echo)))) |
408 (cond ((stringp help-echo) | 339 (cond ((stringp help-echo) |
409 help-echo) | 340 help-echo) |
410 ((and (symbolp help-echo) (fboundp help-echo) | 341 ((and (functionp help-echo) |
411 (stringp (setq help-echo (funcall help-echo widget)))) | 342 (stringp (setq help-echo (funcall help-echo widget)))) |
412 help-echo) | 343 help-echo) |
413 (t | 344 (t |
414 (format "(widget %S :help-echo %S)" widget help-echo))))) | 345 (format "(widget %S :help-echo %S)" widget help-echo))))) |
415 | 346 |
416 (defun widget-specify-sample (widget from to) | 347 (defun widget-specify-sample (widget from to) |
417 ;; Specify sample for WIDGET between FROM and TO. | 348 ;; Specify sample for WIDGET between FROM and TO. |
418 (let ((face (widget-apply widget :sample-face-get)) | 349 (let ((face (widget-apply widget :sample-face-get)) |
419 (overlay (make-overlay from to nil t nil))) | 350 (extent (make-extent from to nil))) |
420 (overlay-put overlay 'face face) | 351 (set-extent-property extent 'start-open t) |
421 (widget-put widget :sample-overlay overlay))) | 352 (set-extent-property extent 'face face) |
353 (widget-put widget :sample-extent extent))) | |
422 | 354 |
423 (defun widget-specify-doc (widget from to) | 355 (defun widget-specify-doc (widget from to) |
424 ;; Specify documentation for WIDGET between FROM and TO. | 356 ;; Specify documentation for WIDGET between FROM and TO. |
425 (let ((overlay (make-overlay from to nil t nil))) | 357 (let ((extent (make-extent from to))) |
426 (overlay-put overlay 'widget-doc widget) | 358 (set-extent-property extent 'start-open t) |
427 (overlay-put overlay 'face widget-documentation-face) | 359 (set-extent-property extent 'widget-doc widget) |
428 (widget-put widget :doc-overlay overlay))) | 360 (set-extent-property extent 'face widget-documentation-face) |
361 (widget-put widget :doc-extent extent))) | |
429 | 362 |
430 (defmacro widget-specify-insert (&rest form) | 363 (defmacro widget-specify-insert (&rest form) |
431 ;; Execute FORM without inheriting any text properties. | 364 ;; Execute FORM without inheriting any text properties. |
432 (` | 365 `(save-restriction |
433 (save-restriction | |
434 (let ((inhibit-read-only t) | 366 (let ((inhibit-read-only t) |
435 result | |
436 before-change-functions | 367 before-change-functions |
437 after-change-functions) | 368 after-change-functions) |
438 (insert "<>") | 369 (insert "<>") |
439 (narrow-to-region (- (point) 2) (point)) | 370 (narrow-to-region (- (point) 2) (point)) |
440 (goto-char (1+ (point-min))) | 371 (goto-char (1+ (point-min))) |
441 (setq result (progn (,@ form))) | 372 ;; We use `prog1' instead of a `result' variable, as the latter |
442 (delete-region (point-min) (1+ (point-min))) | 373 ;; confuses the byte-compiler in some cases (a warning). |
443 (delete-region (1- (point-max)) (point-max)) | 374 (prog1 (progn ,@form) |
444 (goto-char (point-max)) | 375 (delete-region (point-min) (1+ (point-min))) |
445 result)))) | 376 (delete-region (1- (point-max)) (point-max)) |
377 (goto-char (point-max)))))) | |
446 | 378 |
447 (defface widget-inactive-face '((((class grayscale color) | 379 (defface widget-inactive-face '((((class grayscale color) |
448 (background dark)) | 380 (background dark)) |
449 (:foreground "light gray")) | 381 (:foreground "light gray")) |
450 (((class grayscale color) | 382 (((class grayscale color) |
456 :group 'widget-faces) | 388 :group 'widget-faces) |
457 | 389 |
458 (defun widget-specify-inactive (widget from to) | 390 (defun widget-specify-inactive (widget from to) |
459 "Make WIDGET inactive for user modifications." | 391 "Make WIDGET inactive for user modifications." |
460 (unless (widget-get widget :inactive) | 392 (unless (widget-get widget :inactive) |
461 (let ((overlay (make-overlay from to nil t nil))) | 393 (let ((extent (make-extent from to))) |
462 (overlay-put overlay 'face 'widget-inactive-face) | 394 (set-extent-property extent 'start-open t) |
395 (set-extent-property extent 'face 'widget-inactive-face) | |
463 ;; This is disabled, as it makes the mouse cursor change shape. | 396 ;; This is disabled, as it makes the mouse cursor change shape. |
464 ;; (overlay-put overlay 'mouse-face 'widget-inactive-face) | 397 ;(set-extent-property extent 'mouse-face 'widget-inactive-face) |
465 (overlay-put overlay 'evaporate t) | 398 ;; ...actually, in XEmacs, we can easily choose our own pointer |
466 (overlay-put overlay 'priority 100) | 399 ;; shapes. However, the mouse-face of the "inner" extent will |
467 (overlay-put overlay (if (string-match "XEmacs" emacs-version) | 400 ;; still be drawn. |
468 'read-only | 401 (set-extent-property extent 'detachable t) |
469 'modification-hooks) '(widget-overlay-inactive)) | 402 (set-extent-property extent 'priority 100) |
470 (widget-put widget :inactive overlay)))) | 403 (set-extent-property extent 'read-only 't) |
471 | 404 (widget-put widget :inactive extent)))) |
472 (defun widget-overlay-inactive (&rest junk) | 405 |
473 "Ignoring the arguments, signal an error." | 406 ;; We don't have modification functions, so this is unused. |
474 (unless inhibit-read-only | 407 ;(defun widget-overlay-inactive (&rest junk) |
475 (error "Attempt to modify inactive widget"))) | 408 ; "Ignoring the arguments, signal an error." |
409 ; (unless inhibit-read-only | |
410 ; (error "Attempt to modify inactive widget"))) | |
476 | 411 |
477 | 412 |
478 (defun widget-specify-active (widget) | 413 (defun widget-specify-active (widget) |
479 "Make WIDGET active for user modifications." | 414 "Make WIDGET active for user modifications." |
480 (let ((inactive (widget-get widget :inactive))) | 415 (let ((inactive (widget-get widget :inactive))) |
481 (when inactive | 416 (when inactive |
482 (delete-overlay inactive) | 417 (delete-extent inactive) |
483 (widget-put widget :inactive nil)))) | 418 (widget-put widget :inactive nil)))) |
484 | 419 |
420 | |
485 ;;; Widget Properties. | 421 ;;; Widget Properties. |
486 | 422 |
487 (defsubst widget-type (widget) | 423 (defun widget-type (widget) |
488 "Return the type of WIDGET, a symbol." | 424 "Return the type of WIDGET, a symbol." |
489 (car widget)) | 425 (car widget)) |
490 | 426 |
491 (defun widget-put (widget property value) | 427 (when (or (not (fboundp 'widget-put)) |
492 "In WIDGET set PROPERTY to VALUE. | 428 widget-shadow-subrs) |
429 (defun widget-put (widget property value) | |
430 "In WIDGET set PROPERTY to VALUE. | |
493 The value can later be retrived with `widget-get'." | 431 The value can later be retrived with `widget-get'." |
494 (setcdr widget (plist-put (cdr widget) property value))) | 432 (setcdr widget (plist-put (cdr widget) property value)))) |
495 | 433 |
496 (defun widget-get (widget property) | 434 ;; Recoded in C, for efficiency: |
497 "In WIDGET, get the value of PROPERTY. | 435 (when (or (not (fboundp 'widget-get)) |
436 widget-shadow-subrs) | |
437 (defun widget-get (widget property) | |
438 "In WIDGET, get the value of PROPERTY. | |
498 The value could either be specified when the widget was created, or | 439 The value could either be specified when the widget was created, or |
499 later with `widget-put'." | 440 later with `widget-put'." |
500 (let ((missing t) | 441 (let ((missing t) |
501 value tmp) | 442 value tmp) |
502 (while missing | 443 (while missing |
503 (cond ((setq tmp (widget-plist-member (cdr widget) property)) | 444 (cond ((setq tmp (widget-plist-member (cdr widget) property)) |
504 (setq value (car (cdr tmp)) | 445 (setq value (car (cdr tmp)) |
505 missing nil)) | 446 missing nil)) |
506 ((setq tmp (car widget)) | 447 ((setq tmp (car widget)) |
507 (setq widget (get tmp 'widget-type))) | 448 (setq widget (get tmp 'widget-type))) |
508 (t | 449 (t |
509 (setq missing nil)))) | 450 (setq missing nil)))) |
510 value)) | 451 value))) |
511 | 452 |
512 (defun widget-get-indirect (widget property) | 453 (defun widget-get-indirect (widget property) |
513 "In WIDGET, get the value of PROPERTY. | 454 "In WIDGET, get the value of PROPERTY. |
514 If the value is a symbol, return its binding. | 455 If the value is a symbol, return its binding. |
515 Otherwise, just return the value." | 456 Otherwise, just return the value." |
524 t) | 465 t) |
525 ((car widget) | 466 ((car widget) |
526 (widget-member (get (car widget) 'widget-type) property)) | 467 (widget-member (get (car widget) 'widget-type) property)) |
527 (t nil))) | 468 (t nil))) |
528 | 469 |
529 ;;;###autoload | 470 (when (or (not (fboundp 'widget-apply)) |
530 (defun widget-apply (widget property &rest args) | 471 widget-shadow-subrs) |
531 "Apply the value of WIDGET's PROPERTY to the widget itself. | 472 ;;This is in C, so don't ###utoload |
473 (defun widget-apply (widget property &rest args) | |
474 "Apply the value of WIDGET's PROPERTY to the widget itself. | |
532 ARGS are passed as extra arguments to the function." | 475 ARGS are passed as extra arguments to the function." |
533 (apply (widget-get widget property) widget args)) | 476 (apply (widget-get widget property) widget args))) |
534 | 477 |
535 (defun widget-value (widget) | 478 (defun widget-value (widget) |
536 "Extract the current value of WIDGET." | 479 "Extract the current value of WIDGET." |
537 (widget-apply widget | 480 (widget-apply widget |
538 :value-to-external (widget-apply widget :value-get))) | 481 :value-to-external (widget-apply widget :value-get))) |
556 "Apply :action in WIDGET in response to EVENT." | 499 "Apply :action in WIDGET in response to EVENT." |
557 (if (widget-apply widget :active) | 500 (if (widget-apply widget :active) |
558 (widget-apply widget :action event) | 501 (widget-apply widget :action event) |
559 (error "Attempt to perform action on inactive widget"))) | 502 (error "Attempt to perform action on inactive widget"))) |
560 | 503 |
504 | |
561 ;;; Helper functions. | 505 ;;; Helper functions. |
562 ;; | 506 ;; |
563 ;; These are widget specific. | 507 ;; These are widget specific. |
564 | 508 |
565 ;;;###autoload | 509 ;;;###autoload |
595 | 539 |
596 If FUNCTION returns non-nil, the walk is cancelled. | 540 If FUNCTION returns non-nil, the walk is cancelled. |
597 | 541 |
598 The arguments MAPARG, and BUFFER default to nil and (current-buffer), | 542 The arguments MAPARG, and BUFFER default to nil and (current-buffer), |
599 respectively." | 543 respectively." |
600 (let ((cur (point-min)) | 544 (map-extents (lambda (extent ignore) |
601 (widget nil) | 545 ;; If FUNCTION returns non-nil, we bail out |
602 ;; (parent nil) | 546 (funcall function (extent-property extent 'button) maparg)) |
603 (overlays (if buffer | 547 nil nil nil nil nil |
604 (save-excursion (set-buffer buffer) (overlay-lists)) | 548 'button)) |
605 (overlay-lists)))) | 549 |
606 (setq overlays (append (car overlays) (cdr overlays))) | 550 |
607 (while (setq cur (pop overlays)) | |
608 (setq widget (overlay-get cur 'button)) | |
609 (if (and widget (funcall function widget maparg)) | |
610 (setq overlays nil))))) | |
611 | |
612 ;;; Glyphs. | 551 ;;; Glyphs. |
613 | 552 |
614 (defcustom widget-glyph-directory (concat data-directory "custom/") | 553 (defcustom widget-glyph-directory (locate-data-directory "custom") |
615 "Where widget glyphs are located. | 554 "Where widget glyphs are located. |
616 If this variable is nil, widget will try to locate the directory | 555 If this variable is nil, widget will try to locate the directory |
617 automatically." | 556 automatically." |
618 :group 'widgets | 557 :group 'widgets |
619 :type 'directory) | 558 :type 'directory) |
631 :type '(repeat (cons :format "%v" | 570 :type '(repeat (cons :format "%v" |
632 (symbol :tag "Image Format" unknown) | 571 (symbol :tag "Image Format" unknown) |
633 (repeat :tag "Suffixes" | 572 (repeat :tag "Suffixes" |
634 (string :format "%v"))))) | 573 (string :format "%v"))))) |
635 | 574 |
575 (defvar widget-glyph-cache nil | |
576 "Cache of glyphs associated with strings (files).") | |
577 | |
636 (defun widget-glyph-find (image tag) | 578 (defun widget-glyph-find (image tag) |
637 "Create a glyph corresponding to IMAGE with string TAG as fallback. | 579 "Create a glyph corresponding to IMAGE with string TAG as fallback. |
638 IMAGE should either already be a glyph, or be a file name sans | 580 IMAGE can already be a glyph, or a file name sans extension (xpm, |
639 extension (xpm, xbm, gif, jpg, or png) located in | 581 xbm, gif, jpg, or png) located in `widget-glyph-directory', or |
640 `widget-glyph-directory'." | 582 in one of the data directories. |
641 (cond ((not (and image | 583 It can also be a valid image instantiator, in which case it will be |
642 (string-match "XEmacs" emacs-version) | 584 used to make the glyph, with an additional TAG string fallback. |
643 widget-glyph-enable | 585 If IMAGE is a list, it will be given unchanged to `make-glyph'." |
644 (fboundp 'make-glyph) | 586 (cond ((not (and image widget-glyph-enable)) |
645 (fboundp 'locate-file) | 587 ;; We don't want to use glyphs. |
646 image)) | |
647 ;; We don't want or can't use glyphs. | |
648 nil) | 588 nil) |
649 ((and (fboundp 'glyphp) | 589 ((glyphp image) |
650 (glyphp image)) | |
651 ;; Already a glyph. Use it. | 590 ;; Already a glyph. Use it. |
652 image) | 591 image) |
653 ((stringp image) | 592 ((stringp image) |
654 ;; A string. Look it up in relevant directories. | 593 ;; A string. Look it up in the cache first... |
655 (let* ((dirlist (list (or widget-glyph-directory | 594 (or (lax-plist-get widget-glyph-cache image) |
656 (concat data-directory | 595 ;; ...and then in the relevant directories |
657 "custom/")) | 596 (let* ((dirlist (cons (or widget-glyph-directory |
658 data-directory)) | 597 (locate-data-directory "custom")) |
659 (formats widget-image-conversion) | 598 data-directory-list)) |
660 file) | 599 (formats widget-image-conversion) |
661 (while (and formats (not file)) | 600 file) |
662 (when (valid-image-instantiator-format-p (car (car formats))) | 601 (while (and formats (not file)) |
663 (setq file (locate-file image dirlist | 602 (when (valid-image-instantiator-format-p (caar formats)) |
664 (mapconcat 'identity | 603 (setq file (locate-file image dirlist |
665 (cdr (car formats)) | 604 (mapconcat 'identity (cdar formats) |
666 ":")))) | 605 ":")))) |
667 (unless file | 606 (unless file |
668 (setq formats (cdr formats)))) | 607 (pop formats))) |
669 (and file | 608 (when file |
670 ;; We create a glyph with the file as the default image | 609 ;; We create a glyph with the file as the default image |
671 ;; instantiator, and the TAG fallback | 610 ;; instantiator, and the TAG fallback |
672 (make-glyph (list (vector (car (car formats)) ':file file) | 611 (let ((glyph (make-glyph `([,(caar formats) :file ,file] |
673 (vector 'string ':data tag)))))) | 612 [string :data ,tag])))) |
613 ;; Cache the glyph | |
614 (setq widget-glyph-cache | |
615 (lax-plist-put widget-glyph-cache image glyph)) | |
616 ;; ...and return it | |
617 glyph))))) | |
674 ((valid-instantiator-p image 'image) | 618 ((valid-instantiator-p image 'image) |
675 ;; A valid image instantiator (e.g. [gif :file "somefile"] etc.) | 619 ;; A valid image instantiator (e.g. [gif :file "somefile"] etc.) |
676 (make-glyph (list image | 620 (make-glyph `(,image [string :data ,tag]))) |
677 (vector 'string ':data tag)))) | |
678 ((consp image) | 621 ((consp image) |
679 ;; This could be virtually anything. Let `make-glyph' sort it out. | 622 ;; This could be virtually anything. Let `make-glyph' sort it out. |
680 (make-glyph image)) | 623 (make-glyph image)) |
681 (t | 624 (t |
682 ;; Oh well. | 625 ;; Oh well. |
683 nil))) | 626 nil))) |
684 | 627 |
685 (defun widget-glyph-insert (widget tag image &optional down inactive) | 628 (defun widget-glyph-insert (widget tag image &optional down inactive) |
686 "In WIDGET, insert the text TAG or, if supported, IMAGE. | 629 "In WIDGET, insert the text TAG or, if supported, IMAGE. |
687 IMAGE should either be a glyph, an image instantiator, or an image file | 630 IMAGE should either be a glyph, an image instantiator, an image file |
688 name sans extension (xpm, xbm, gif, jpg, or png) located in | 631 name sans extension (xpm, xbm, gif, jpg, or png) located in |
689 `widget-glyph-directory'. | 632 `widget-glyph-directory', or anything else allowed by |
633 `widget-glyph-find'. | |
690 | 634 |
691 Optional arguments DOWN and INACTIVE is used instead of IMAGE when the | 635 Optional arguments DOWN and INACTIVE is used instead of IMAGE when the |
692 glyph is pressed or inactive, respectively. | 636 glyph is pressed or inactive, respectively. |
693 | |
694 WARNING: If you call this with a glyph, and you want the user to be | |
695 able to invoke the glyph, make sure it is unique. If you use the | |
696 same glyph for multiple widgets, invoking any of the glyphs will | |
697 cause the last created widget to be invoked. | |
698 | 637 |
699 Instead of an instantiator, you can also use a list of instantiators, | 638 Instead of an instantiator, you can also use a list of instantiators, |
700 or whatever `make-glyph' will accept. However, in that case you must | 639 or whatever `make-glyph' will accept. However, in that case you must |
701 provide the fallback TAG as a part of the instantiator yourself." | 640 provide the fallback TAG as a part of the instantiator yourself." |
702 (let ((glyph (widget-glyph-find image tag))) | 641 (let ((glyph (widget-glyph-find image tag))) |
703 (if glyph | 642 (if glyph |
704 (widget-glyph-insert-glyph widget | 643 (widget-glyph-insert-glyph widget glyph |
705 glyph | |
706 (widget-glyph-find down tag) | 644 (widget-glyph-find down tag) |
707 (widget-glyph-find inactive tag)) | 645 (widget-glyph-find inactive tag)) |
708 (insert tag)))) | 646 (insert tag)))) |
709 | 647 |
710 (defun widget-glyph-insert-glyph (widget glyph &optional down inactive) | 648 (defun widget-glyph-insert-glyph (widget glyph &optional down inactive) |
711 "In WIDGET, insert GLYPH. | 649 "In WIDGET, insert GLYPH. |
712 If optional arguments DOWN and INACTIVE are given, they should be | 650 If optional arguments DOWN and INACTIVE are given, they should be |
713 glyphs used when the widget is pushed and inactive, respectively." | 651 glyphs used when the widget is pushed and inactive, respectively." |
714 (when widget | |
715 (set-glyph-property glyph 'widget widget) | |
716 (when down | |
717 (set-glyph-property down 'widget widget)) | |
718 (when inactive | |
719 (set-glyph-property inactive 'widget widget))) | |
720 (insert "*") | 652 (insert "*") |
721 (let ((ext (make-extent (point) (1- (point)))) | 653 (let ((extent (make-extent (point) (1- (point)))) |
722 (help-echo (and widget (widget-get widget :help-echo)))) | 654 (help-echo (and widget (widget-get widget :help-echo)))) |
723 (set-extent-property ext 'invisible t) | 655 (set-extent-property extent 'widget widget) |
724 (set-extent-property ext 'start-open t) | 656 (set-extent-property extent 'invisible t) |
725 (set-extent-property ext 'end-open t) | 657 (set-extent-property extent 'start-open t) |
726 (set-extent-end-glyph ext glyph) | 658 (set-extent-property extent 'end-open t) |
659 (set-extent-end-glyph extent glyph) | |
727 (when help-echo | 660 (when help-echo |
728 (set-extent-property ext 'balloon-help help-echo) | 661 (set-extent-property extent 'balloon-help help-echo) |
729 (set-extent-property ext 'help-echo help-echo))) | 662 (set-extent-property extent 'help-echo help-echo))) |
730 (when widget | 663 (when widget |
731 (widget-put widget :glyph-up glyph) | 664 (widget-put widget :glyph-up glyph) |
732 (when down (widget-put widget :glyph-down down)) | 665 (when down (widget-put widget :glyph-down down)) |
733 (when inactive (widget-put widget :glyph-inactive inactive)))) | 666 (when inactive (widget-put widget :glyph-inactive inactive)))) |
734 | 667 |
668 | |
735 ;;; Buttons. | 669 ;;; Buttons. |
736 | 670 |
737 (defgroup widget-button nil | 671 (defgroup widget-button nil |
738 "The look of various kinds of buttons." | 672 "The look of various kinds of buttons." |
739 :group 'widgets) | 673 :group 'widgets) |
746 (defcustom widget-button-suffix "" | 680 (defcustom widget-button-suffix "" |
747 "String used as suffix for buttons." | 681 "String used as suffix for buttons." |
748 :type 'string | 682 :type 'string |
749 :group 'widget-button) | 683 :group 'widget-button) |
750 | 684 |
685 | |
751 ;;; Creating Widgets. | 686 ;;; Creating Widgets. |
752 | 687 |
753 ;;;###autoload | 688 ;;;###autoload |
754 (defun widget-create (type &rest args) | 689 (defun widget-create (type &rest args) |
755 "Create widget of TYPE. | 690 "Create widget of TYPE. |
838 ;; Convert the :value to internal format. | 773 ;; Convert the :value to internal format. |
839 (if (widget-member widget :value) | 774 (if (widget-member widget :value) |
840 (let ((value (widget-get widget :value))) | 775 (let ((value (widget-get widget :value))) |
841 (widget-put widget | 776 (widget-put widget |
842 :value (widget-apply widget :value-to-internal value)))) | 777 :value (widget-apply widget :value-to-internal value)))) |
843 ;; Return the newly create widget. | 778 ;; Return the newly created widget. |
844 widget)) | 779 widget)) |
845 | 780 |
846 (defun widget-insert (&rest args) | 781 (defun widget-insert (&rest args) |
847 "Call `insert' with ARGS and make the text read only." | 782 "Call `insert' with ARGS and make the text read only." |
848 (let ((inhibit-read-only t) | 783 (let ((inhibit-read-only t) |
877 and TO will be used as the widgets end points, as well as the widgets | 812 and TO will be used as the widgets end points, as well as the widgets |
878 button end points." | 813 button end points." |
879 (apply 'widget-convert-text type from to from to args)) | 814 (apply 'widget-convert-text type from to from to args)) |
880 | 815 |
881 (defun widget-leave-text (widget) | 816 (defun widget-leave-text (widget) |
882 "Remove markers and overlays from WIDGET and its children." | 817 "Remove markers and extents from WIDGET and its children." |
883 (let ((from (widget-get widget :from)) | 818 (let ((from (widget-get widget :from)) |
884 (to (widget-get widget :to)) | 819 (to (widget-get widget :to)) |
885 (button (widget-get widget :button-overlay)) | 820 (button (widget-get widget :button-extent)) |
886 (sample (widget-get widget :sample-overlay)) | 821 (sample (widget-get widget :sample-extent)) |
887 (doc (widget-get widget :doc-overlay)) | 822 (doc (widget-get widget :doc-extent)) |
888 (field (widget-get widget :field-overlay)) | 823 (field (widget-get widget :field-extent)) |
889 (children (widget-get widget :children))) | 824 (children (widget-get widget :children))) |
890 (set-marker from nil) | 825 (set-marker from nil) |
891 (set-marker to nil) | 826 (set-marker to nil) |
827 ;; Maybe we should delete the extents here? As this code doesn't | |
828 ;; remove them from widget structures, maybe it's safer to just | |
829 ;; detach them. That's what `delete-overlay' did. | |
892 (when button | 830 (when button |
893 (delete-overlay button)) | 831 (detach-extent button)) |
894 (when sample | 832 (when sample |
895 (delete-overlay sample)) | 833 (detach-extent sample)) |
896 (when doc | 834 (when doc |
897 (delete-overlay doc)) | 835 (detach-extent doc)) |
898 (when field | 836 (when field |
899 (delete-overlay field)) | 837 (detach-extent field)) |
900 (mapcar 'widget-leave-text children))) | 838 (mapc 'widget-leave-text children))) |
901 | 839 |
840 | |
902 ;;; Keymap and Commands. | 841 ;;; Keymap and Commands. |
903 | 842 |
904 (defvar widget-keymap nil | 843 (defvar widget-keymap nil |
905 "Keymap containing useful binding for buffers containing widgets. | 844 "Keymap containing useful binding for buffers containing widgets. |
906 Recommended as a parent keymap for modes using widgets.") | 845 Recommended as a parent keymap for modes using widgets.") |
907 | 846 |
908 (unless widget-keymap | 847 (unless widget-keymap |
909 (setq widget-keymap (make-sparse-keymap)) | 848 (setq widget-keymap (make-sparse-keymap)) |
910 (define-key widget-keymap "\t" 'widget-forward) | 849 (define-key widget-keymap [tab] 'widget-forward) |
911 (define-key widget-keymap [(shift tab)] 'widget-backward) | 850 (define-key widget-keymap [(shift tab)] 'widget-backward) |
851 (define-key widget-keymap [(meta tab)] 'widget-backward) | |
912 (define-key widget-keymap [backtab] 'widget-backward) | 852 (define-key widget-keymap [backtab] 'widget-backward) |
913 (if (string-match "XEmacs" emacs-version) | 853 ;;Glyph support. |
914 (progn | 854 (define-key widget-keymap [button1] 'widget-button1-click) |
915 ;;Glyph support. | 855 (define-key widget-keymap [button2] 'widget-button-click) |
916 (define-key widget-keymap [button1] 'widget-button1-click) | |
917 (define-key widget-keymap [button2] 'widget-button-click)) | |
918 (define-key widget-keymap [down-mouse-2] 'widget-button-click)) | |
919 (define-key widget-keymap "\C-m" 'widget-button-press)) | 856 (define-key widget-keymap "\C-m" 'widget-button-press)) |
920 | 857 |
921 (defvar widget-global-map global-map | 858 (defvar widget-global-map global-map |
922 "Keymap used for events the widget does not handle themselves.") | 859 "Keymap used for events the widget does not handle themselves.") |
923 (make-variable-buffer-local 'widget-global-map) | 860 (make-variable-buffer-local 'widget-global-map) |
924 | 861 |
925 (defvar widget-field-keymap nil | 862 (defvar widget-field-keymap nil |
926 "Keymap used inside an editable field.") | 863 "Keymap used inside an editable field.") |
927 | 864 |
928 (unless widget-field-keymap | 865 (unless widget-field-keymap |
929 (setq widget-field-keymap (copy-keymap widget-keymap)) | 866 (setq widget-field-keymap (make-sparse-keymap)) |
930 (unless (string-match "XEmacs" (emacs-version)) | 867 (set-keymap-parents widget-field-keymap global-map) |
931 (define-key widget-field-keymap [menu-bar] 'nil)) | |
932 (define-key widget-field-keymap "\C-k" 'widget-kill-line) | 868 (define-key widget-field-keymap "\C-k" 'widget-kill-line) |
933 (define-key widget-field-keymap "\M-\t" 'widget-complete) | 869 (define-key widget-field-keymap [(meta tab)] 'widget-complete) |
870 (define-key widget-field-keymap [tab] 'widget-forward) | |
871 (define-key widget-field-keymap [(shift tab)] 'widget-backward) | |
934 (define-key widget-field-keymap "\C-m" 'widget-field-activate) | 872 (define-key widget-field-keymap "\C-m" 'widget-field-activate) |
935 (define-key widget-field-keymap "\C-a" 'widget-beginning-of-line) | 873 (define-key widget-field-keymap "\C-a" 'widget-beginning-of-line) |
936 (define-key widget-field-keymap "\C-e" 'widget-end-of-line) | 874 (define-key widget-field-keymap "\C-e" 'widget-end-of-line) |
937 (set-keymap-parent widget-field-keymap global-map)) | 875 (define-key widget-field-keymap "\C-t" 'widget-transpose-chars)) |
938 | 876 |
939 (defvar widget-text-keymap nil | 877 (defvar widget-text-keymap nil |
940 "Keymap used inside a text field.") | 878 "Keymap used inside a text field.") |
941 | 879 |
942 (unless widget-text-keymap | 880 (unless widget-text-keymap |
943 (setq widget-text-keymap (copy-keymap widget-keymap)) | 881 (setq widget-text-keymap (make-sparse-keymap)) |
944 (unless (string-match "XEmacs" (emacs-version)) | 882 (set-keymap-parents widget-field-keymap global-map) |
945 (define-key widget-text-keymap [menu-bar] 'nil)) | |
946 (define-key widget-text-keymap "\C-a" 'widget-beginning-of-line) | 883 (define-key widget-text-keymap "\C-a" 'widget-beginning-of-line) |
947 (define-key widget-text-keymap "\C-e" 'widget-end-of-line) | 884 (define-key widget-text-keymap "\C-e" 'widget-end-of-line) |
948 (set-keymap-parent widget-text-keymap global-map)) | 885 (define-key widget-text-keymap "\C-t" 'widget-transpose-chars)) |
886 | |
949 | 887 |
950 (defun widget-field-activate (pos &optional event) | 888 (defun widget-field-activate (pos &optional event) |
951 "Invoke the ediable field at point." | 889 "Invoke the ediable field at point." |
952 (interactive "@d") | 890 (interactive "@d") |
953 (let ((field (get-char-property pos 'field))) | 891 (let ((field (get-char-property pos 'field))) |
965 :group 'widget-faces) | 903 :group 'widget-faces) |
966 | 904 |
967 (defun widget-button-click (event) | 905 (defun widget-button-click (event) |
968 "Invoke button below mouse pointer." | 906 "Invoke button below mouse pointer." |
969 (interactive "@e") | 907 (interactive "@e") |
970 (cond ((and (fboundp 'event-glyph) | 908 (cond ((event-glyph event) |
971 (event-glyph event)) | |
972 (widget-glyph-click event)) | 909 (widget-glyph-click event)) |
973 ((widget-event-point event) | 910 ((widget-event-point event) |
974 (let* ((pos (widget-event-point event)) | 911 (let* ((pos (widget-event-point event)) |
975 (button (get-char-property pos 'button))) | 912 (button (get-char-property pos 'button))) |
976 (if button | 913 (if button |
977 (let* ((overlay (widget-get button :button-overlay)) | 914 (let* ((extent (widget-get button :button-extent)) |
978 (face (overlay-get overlay 'face)) | 915 (face (extent-property extent 'face)) |
979 (mouse-face (overlay-get overlay 'mouse-face))) | 916 (mouse-face (extent-property extent 'mouse-face))) |
980 (unwind-protect | 917 (unwind-protect |
981 (let ((track-mouse t)) | 918 (progn |
982 (overlay-put overlay | 919 (set-extent-property extent 'face |
983 'face 'widget-button-pressed-face) | 920 'widget-button-pressed-face) |
984 (overlay-put overlay | 921 (set-extent-property extent 'mouse-face |
985 'mouse-face 'widget-button-pressed-face) | 922 'widget-button-pressed-face) |
986 (unless (widget-apply button :mouse-down-action event) | 923 (unless (widget-apply button :mouse-down-action event) |
987 (while (not (button-release-event-p event)) | 924 (while (not (button-release-event-p event)) |
988 (setq event (widget-read-event) | 925 (setq event (next-event) |
989 pos (widget-event-point event)) | 926 pos (widget-event-point event)) |
990 (if (and pos | 927 (if (and pos |
991 (eq (get-char-property pos 'button) | 928 (eq (get-char-property pos 'button) |
992 button)) | 929 button)) |
993 (progn | 930 (progn |
994 (overlay-put overlay | 931 (set-extent-property extent 'face |
995 'face | 932 'widget-button-pressed-face) |
996 'widget-button-pressed-face) | 933 (set-extent-property extent 'mouse-face |
997 (overlay-put overlay | 934 'widget-button-pressed-face)) |
998 'mouse-face | 935 (set-extent-property extent 'face face) |
999 'widget-button-pressed-face)) | 936 (set-extent-property extent |
1000 (overlay-put overlay 'face face) | 937 'mouse-face mouse-face)))) |
1001 (overlay-put overlay 'mouse-face mouse-face)))) | |
1002 (when (and pos | 938 (when (and pos |
1003 (eq (get-char-property pos 'button) button)) | 939 (eq (get-char-property pos 'button) button)) |
1004 (widget-apply-action button event))) | 940 (widget-apply-action button event))) |
1005 (overlay-put overlay 'face face) | 941 (set-extent-property extent 'face face) |
1006 (overlay-put overlay 'mouse-face mouse-face))) | 942 (set-extent-property extent 'mouse-face mouse-face))) |
1007 (let ((up t) | 943 (let ((up t) |
1008 command) | 944 command) |
1009 ;; Find the global command to run, and check whether it | 945 ;; Find the global command to run, and check whether it |
1010 ;; is bound to an up event. | 946 ;; is bound to an up event. |
1011 (cond ((setq command ;down event | 947 (cond ((setq command ;down event |
1012 (lookup-key widget-global-map [ button2 ])) | 948 (lookup-key widget-global-map [button2])) |
1013 (setq up nil)) | |
1014 ((setq command ;down event | |
1015 (lookup-key widget-global-map [ down-mouse-2 ])) | |
1016 (setq up nil)) | 949 (setq up nil)) |
1017 ((setq command ;up event | 950 ((setq command ;up event |
1018 (lookup-key widget-global-map [ button2up ]))) | 951 (lookup-key widget-global-map [button2up])))) |
1019 ((setq command ;up event | |
1020 (lookup-key widget-global-map [ mouse-2])))) | |
1021 (when up | 952 (when up |
1022 ;; Don't execute up events twice. | 953 ;; Don't execute up events twice. |
1023 (while (not (button-release-event-p event)) | 954 (while (not (button-release-event-p event)) |
1024 (setq event (widget-read-event)))) | 955 (setq event (next-event)))) |
1025 (when command | 956 (when command |
1026 (call-interactively command)))))) | 957 (call-interactively command)))))) |
1027 (t | 958 (t |
1028 (message "You clicked somewhere weird.")))) | 959 (message "You clicked somewhere weird.")))) |
1029 | 960 |
1030 (defun widget-button1-click (event) | 961 (defun widget-button1-click (event) |
1031 "Invoke glyph below mouse pointer." | 962 "Invoke glyph below mouse pointer." |
1032 (interactive "@e") | 963 (interactive "@e") |
1033 (if (and (fboundp 'event-glyph) | 964 (if (event-glyph event) |
1034 (event-glyph event)) | |
1035 (widget-glyph-click event) | 965 (widget-glyph-click event) |
1036 (call-interactively (lookup-key widget-global-map (this-command-keys))))) | 966 (let ((command (lookup-key widget-global-map (this-command-keys)))) |
967 (and (commandp command) | |
968 (call-interactively command))))) | |
1037 | 969 |
1038 (defun widget-glyph-click (event) | 970 (defun widget-glyph-click (event) |
1039 "Handle click on a glyph." | 971 "Handle click on a glyph." |
1040 (let* ((glyph (event-glyph event)) | 972 (let* ((glyph (event-glyph event)) |
1041 (widget (glyph-property glyph 'widget)) | |
1042 (extent (event-glyph-extent event)) | 973 (extent (event-glyph-extent event)) |
974 (widget (extent-property extent 'widget)) | |
1043 (down-glyph (or (and widget (widget-get widget :glyph-down)) glyph)) | 975 (down-glyph (or (and widget (widget-get widget :glyph-down)) glyph)) |
1044 (up-glyph (or (and widget (widget-get widget :glyph-up)) glyph)) | 976 (up-glyph (or (and widget (widget-get widget :glyph-up)) glyph)) |
1045 (last event)) | 977 (last event)) |
1046 ;; Wait for the release. | 978 ;; Wait for the release. |
1047 (while (not (button-release-event-p last)) | 979 (while (not (button-release-event-p last)) |
1052 ;; Release glyph. | 984 ;; Release glyph. |
1053 (when down-glyph | 985 (when down-glyph |
1054 (set-extent-property extent 'end-glyph up-glyph)) | 986 (set-extent-property extent 'end-glyph up-glyph)) |
1055 ;; Apply widget action. | 987 ;; Apply widget action. |
1056 (when (eq extent (event-glyph-extent last)) | 988 (when (eq extent (event-glyph-extent last)) |
1057 (let ((widget (glyph-property (event-glyph event) 'widget))) | 989 (let ((widget (extent-property (event-glyph-extent event) 'widget))) |
1058 (cond ((null widget) | 990 (cond ((null widget) |
1059 (message "You clicked on a glyph.")) | 991 (message "You clicked on a glyph.")) |
1060 ((not (widget-apply widget :active)) | 992 ((not (widget-apply widget :active)) |
1061 (message "This glyph is inactive.")) | 993 (message "This glyph is inactive.")) |
1062 (t | 994 (t |
1075 (defun widget-tabable-at (&optional pos) | 1007 (defun widget-tabable-at (&optional pos) |
1076 "Return the tabable widget at POS, or nil. | 1008 "Return the tabable widget at POS, or nil. |
1077 POS defaults to the value of (point)." | 1009 POS defaults to the value of (point)." |
1078 (unless pos | 1010 (unless pos |
1079 (setq pos (point))) | 1011 (setq pos (point))) |
1080 (let ((widget (or (get-char-property (point) 'button) | 1012 (let ((widget (widget-at pos))) |
1081 (get-char-property (point) 'field)))) | |
1082 (if widget | 1013 (if widget |
1083 (let ((order (widget-get widget :tab-order))) | 1014 (let ((order (widget-get widget :tab-order))) |
1084 (if order | 1015 (if order |
1085 (if (>= order 0) | 1016 (if (>= order 0) |
1086 widget | 1017 widget |
1087 nil) | 1018 nil) |
1088 widget)) | 1019 widget)) |
1089 nil))) | 1020 nil))) |
1090 | 1021 |
1091 (defcustom widget-use-overlay-change (string-match "XEmacs" emacs-version) | 1022 ;; Return the button or field extent at point. |
1092 "If non-nil, use overlay change functions to tab around in the buffer. | 1023 (defun widget-button-or-field-extent (pos) |
1093 This is much faster, but doesn't work reliably on Emacs 19.34." | 1024 (or (and (get-char-property pos 'button) |
1094 :type 'boolean | 1025 (widget-get (get-char-property pos 'button) |
1095 :group 'widgets) | 1026 :button-extent)) |
1027 (and (get-char-property pos 'field) | |
1028 (widget-get (get-char-property pos 'field) | |
1029 :field-extent)))) | |
1030 | |
1031 (defun widget-next-button-or-field (pos) | |
1032 "Find the next button, or field, and return its start position. | |
1033 If none is found, return (point-max). | |
1034 Internal function, don't use it outside `wid-edit'." | |
1035 (let* ((at-point (widget-button-or-field-extent pos)) | |
1036 (extent (map-extents | |
1037 (lambda (ext ignore) | |
1038 (if (or (extent-property ext 'button) | |
1039 (extent-property ext 'field)) | |
1040 ext | |
1041 nil)) | |
1042 nil (if at-point (extent-end-position at-point) pos) nil))) | |
1043 (if extent | |
1044 (extent-start-position extent) | |
1045 (point-max)))) | |
1046 | |
1047 (defun widget-previous-button-or-field (pos) | |
1048 "Find the previous button, or field, and return its start position. | |
1049 If none is found, return (point-min). | |
1050 Internal function, don't use it outside `wid-edit'." | |
1051 (let* ((at-point (widget-button-or-field-extent pos)) | |
1052 previous-extent) | |
1053 (map-extents | |
1054 (lambda (ext ignore) | |
1055 (when (or (extent-property ext 'button) | |
1056 (extent-property ext 'field)) | |
1057 (if (eq ext at-point) | |
1058 previous-extent | |
1059 (setq previous-extent ext) | |
1060 nil))) | |
1061 nil nil pos) | |
1062 (if previous-extent | |
1063 (extent-start-position previous-extent) | |
1064 (point-min)))) | |
1096 | 1065 |
1097 (defun widget-move (arg) | 1066 (defun widget-move (arg) |
1098 "Move point to the ARG next field or button. | 1067 "Move point to the ARG next field or button. |
1099 ARG may be negative to move backward." | 1068 ARG may be negative to move backward." |
1100 (or (bobp) (> arg 0) (backward-char)) | |
1101 (let ((pos (point)) | 1069 (let ((pos (point)) |
1102 (number arg) | 1070 (number arg) |
1103 (old (widget-tabable-at))) | 1071 (old (widget-tabable-at))) |
1104 ;; Forward. | 1072 ;; Forward. |
1105 (while (> arg 0) | 1073 (while (> arg 0) |
1106 (cond ((eobp) | 1074 (goto-char (if (eobp) |
1107 (goto-char (point-min))) | 1075 (point-min) |
1108 (widget-use-overlay-change | 1076 (widget-next-button-or-field (point)))) |
1109 (goto-char (next-overlay-change (point)))) | |
1110 (t | |
1111 (forward-char 1))) | |
1112 (and (eq pos (point)) | 1077 (and (eq pos (point)) |
1113 (eq arg number) | 1078 (eq arg number) |
1114 (error "No buttons or fields found")) | 1079 (error "No buttons or fields found")) |
1115 (let ((new (widget-tabable-at))) | 1080 (let ((new (widget-tabable-at))) |
1116 (when new | 1081 (when new |
1117 (unless (eq new old) | 1082 (unless (eq new old) |
1118 (setq arg (1- arg)) | 1083 (setq arg (1- arg)) |
1119 (setq old new))))) | 1084 (setq old new))))) |
1120 ;; Backward. | 1085 ;; Backward. |
1121 (while (< arg 0) | 1086 (while (< arg 0) |
1122 (cond ((bobp) | 1087 (goto-char (if (bobp) |
1123 (goto-char (point-max))) | 1088 (point-max) |
1124 (widget-use-overlay-change | 1089 (widget-previous-button-or-field (point)))) |
1125 (goto-char (previous-overlay-change (point)))) | |
1126 (t | |
1127 (backward-char 1))) | |
1128 (and (eq pos (point)) | 1090 (and (eq pos (point)) |
1129 (eq arg number) | 1091 (eq arg number) |
1130 (error "No buttons or fields found")) | 1092 (error "No buttons or fields found")) |
1131 (let ((new (widget-tabable-at))) | 1093 (let ((new (widget-tabable-at))) |
1132 (when new | 1094 (when new |
1133 (unless (eq new old) | 1095 (unless (eq new old) |
1134 (setq arg (1+ arg)))))) | 1096 (incf arg))))) |
1135 (let ((new (widget-tabable-at))) | 1097 (let ((new (widget-tabable-at))) |
1136 (while (eq (widget-tabable-at) new) | 1098 (goto-char (extent-start-position (or (widget-get new :button-extent) |
1137 (backward-char))) | 1099 (widget-get new :field-extent)))))) |
1138 (forward-char)) | |
1139 (widget-echo-help (point)) | 1100 (widget-echo-help (point)) |
1140 (run-hooks 'widget-move-hook)) | 1101 (run-hooks 'widget-move-hook)) |
1141 | 1102 |
1142 (defun widget-forward (arg) | 1103 (defun widget-forward (arg) |
1143 "Move point to the next field or button. | 1104 "Move point to the next field or button. |
1153 (run-hooks 'widget-backward-hook) | 1114 (run-hooks 'widget-backward-hook) |
1154 (widget-move (- arg))) | 1115 (widget-move (- arg))) |
1155 | 1116 |
1156 (defun widget-beginning-of-line () | 1117 (defun widget-beginning-of-line () |
1157 "Go to beginning of field or beginning of line, whichever is first." | 1118 "Go to beginning of field or beginning of line, whichever is first." |
1158 (interactive) | 1119 (interactive "_") |
1159 (let* ((field (widget-field-find (point))) | 1120 (let* ((field (widget-field-find (point))) |
1160 (start (and field (widget-field-start field)))) | 1121 (start (and field (widget-field-start field)))) |
1161 (if (and start (not (eq start (point)))) | 1122 (if (and start (not (eq start (point)))) |
1162 (goto-char start) | 1123 (goto-char start) |
1163 (call-interactively 'beginning-of-line))) | 1124 (call-interactively 'beginning-of-line)))) |
1164 ;; XEmacs: preserve the region | |
1165 (setq zmacs-region-stays t)) | |
1166 | 1125 |
1167 (defun widget-end-of-line () | 1126 (defun widget-end-of-line () |
1168 "Go to end of field or end of line, whichever is first." | 1127 "Go to end of field or end of line, whichever is first." |
1169 (interactive) | 1128 (interactive "_") |
1170 (let* ((field (widget-field-find (point))) | 1129 (let* ((field (widget-field-find (point))) |
1171 (end (and field (widget-field-end field)))) | 1130 (end (and field (widget-field-end field)))) |
1172 (if (and end (not (eq end (point)))) | 1131 (if (and end (not (eq end (point)))) |
1173 (goto-char end) | 1132 (goto-char end) |
1174 (call-interactively 'end-of-line))) | 1133 (call-interactively 'end-of-line)))) |
1175 ;; XEmacs: preserve the region | |
1176 (setq zmacs-region-stays t)) | |
1177 | 1134 |
1178 (defun widget-kill-line () | 1135 (defun widget-kill-line () |
1179 "Kill to end of field or end of line, whichever is first." | 1136 "Kill to end of field or end of line, whichever is first." |
1180 (interactive) | 1137 (interactive) |
1181 (let* ((field (widget-field-find (point))) | 1138 (let* ((field (widget-field-find (point))) |
1183 (end (and field (widget-field-end field)))) | 1140 (end (and field (widget-field-end field)))) |
1184 (if (and field (> newline end)) | 1141 (if (and field (> newline end)) |
1185 (kill-region (point) end) | 1142 (kill-region (point) end) |
1186 (call-interactively 'kill-line)))) | 1143 (call-interactively 'kill-line)))) |
1187 | 1144 |
1145 (defun widget-transpose-chars (arg) | |
1146 "Like `transpose-chars', but works correctly at end of widget." | |
1147 (interactive "*P") | |
1148 (let* ((field (widget-field-find (point))) | |
1149 (start (and field (widget-field-start field))) | |
1150 (end (and field (widget-field-end field))) | |
1151 (last-non-space (and start end | |
1152 (save-excursion | |
1153 (goto-char end) | |
1154 (skip-chars-backward " \t\n" start) | |
1155 (point))))) | |
1156 (if (and last-non-space | |
1157 (= last-non-space (1+ start))) | |
1158 ;; 1-character field | |
1159 nil | |
1160 (when (and (null arg) | |
1161 (= last-non-space (point))) | |
1162 (forward-char -1)) | |
1163 (transpose-chars arg)))) | |
1164 | |
1188 (defcustom widget-complete-field (lookup-key global-map "\M-\t") | 1165 (defcustom widget-complete-field (lookup-key global-map "\M-\t") |
1189 "Default function to call for completion inside fields." | 1166 "Default function to call for completion inside fields." |
1190 :options '(ispell-complete-word complete-tag lisp-complete-symbol) | 1167 :options '(ispell-complete-word complete-tag lisp-complete-symbol) |
1191 :type 'function | 1168 :type 'function |
1192 :group 'widgets) | 1169 :group 'widgets) |
1198 (let ((field (widget-field-find (point)))) | 1175 (let ((field (widget-field-find (point)))) |
1199 (if field | 1176 (if field |
1200 (widget-apply field :complete) | 1177 (widget-apply field :complete) |
1201 (error "Not in an editable field")))) | 1178 (error "Not in an editable field")))) |
1202 | 1179 |
1180 | |
1203 ;;; Setting up the buffer. | 1181 ;;; Setting up the buffer. |
1204 | 1182 |
1205 (defvar widget-field-new nil) | 1183 (defvar widget-field-new nil) |
1206 ;; List of all newly created editable fields in the buffer. | 1184 ;; List of all newly created editable fields in the buffer. |
1207 (make-variable-buffer-local 'widget-field-new) | 1185 (make-variable-buffer-local 'widget-field-new) |
1218 field) | 1196 field) |
1219 (while widget-field-new | 1197 (while widget-field-new |
1220 (setq field (car widget-field-new) | 1198 (setq field (car widget-field-new) |
1221 widget-field-new (cdr widget-field-new) | 1199 widget-field-new (cdr widget-field-new) |
1222 widget-field-list (cons field widget-field-list)) | 1200 widget-field-list (cons field widget-field-list)) |
1223 (let ((from (car (widget-get field :field-overlay))) | 1201 (let ((extent (widget-get field :field-extent))) |
1224 (to (cdr (widget-get field :field-overlay)))) | 1202 (widget-specify-field field |
1225 (widget-specify-field field | 1203 (extent-start-position extent) |
1226 (marker-position from) (marker-position to)) | 1204 (extent-end-position extent)) |
1227 (set-marker from nil) | 1205 (delete-extent extent)))) |
1228 (set-marker to nil)))) | |
1229 (widget-clear-undo) | 1206 (widget-clear-undo) |
1230 (widget-add-change)) | 1207 (widget-add-change)) |
1231 | 1208 |
1232 (defvar widget-field-last nil) | 1209 (defvar widget-field-last nil) |
1233 ;; Last field containing point. | 1210 ;; Last field containing point. |
1237 ;; The widget data before the change. | 1214 ;; The widget data before the change. |
1238 (make-variable-buffer-local 'widget-field-was) | 1215 (make-variable-buffer-local 'widget-field-was) |
1239 | 1216 |
1240 (defun widget-field-buffer (widget) | 1217 (defun widget-field-buffer (widget) |
1241 "Return the start of WIDGET's editing field." | 1218 "Return the start of WIDGET's editing field." |
1242 (let ((overlay (widget-get widget :field-overlay))) | 1219 (let ((extent (widget-get widget :field-extent))) |
1243 (and overlay (overlay-buffer overlay)))) | 1220 (and extent (extent-object extent)))) |
1244 | 1221 |
1245 (defun widget-field-start (widget) | 1222 (defun widget-field-start (widget) |
1246 "Return the start of WIDGET's editing field." | 1223 "Return the start of WIDGET's editing field." |
1247 (let ((overlay (widget-get widget :field-overlay))) | 1224 (let ((extent (widget-get widget :field-extent))) |
1248 (and overlay (overlay-start overlay)))) | 1225 (and extent (extent-start-position extent)))) |
1249 | 1226 |
1250 (defun widget-field-end (widget) | 1227 (defun widget-field-end (widget) |
1251 "Return the end of WIDGET's editing field." | 1228 "Return the end of WIDGET's editing field." |
1252 (let ((overlay (widget-get widget :field-overlay))) | 1229 (let ((extent (widget-get widget :field-extent))) |
1253 ;; Don't subtract one if local-map works at the end of the overlay. | 1230 ;; Don't subtract one if local-map works at the end of the extent. |
1254 (and overlay (if (or widget-field-add-space | 1231 (and extent (if (or widget-field-add-space |
1255 (null (widget-get widget :size))) | 1232 (null (widget-get widget :size))) |
1256 (1- (overlay-end overlay)) | 1233 (1- (extent-end-position extent)) |
1257 (overlay-end overlay))))) | 1234 (extent-end-position extent))))) |
1258 | 1235 |
1259 (defun widget-field-find (pos) | 1236 (defun widget-field-find (pos) |
1260 "Return the field at POS. | 1237 "Return the field at POS. |
1261 Unlike (get-char-property POS 'field) this, works with empty fields too." | 1238 Unlike (get-char-property POS 'field) this, works with empty fields too." |
1262 (let ((fields widget-field-list) | 1239 (let ((fields widget-field-list) |
1338 (while (< begin end) | 1315 (while (< begin end) |
1339 (let ((old (char-after begin))) | 1316 (let ((old (char-after begin))) |
1340 (unless (eq old secret) | 1317 (unless (eq old secret) |
1341 (subst-char-in-region begin (1+ begin) old secret) | 1318 (subst-char-in-region begin (1+ begin) old secret) |
1342 (put-text-property begin (1+ begin) 'secret old)) | 1319 (put-text-property begin (1+ begin) 'secret old)) |
1343 (setq begin (1+ begin))))))) | 1320 (incf begin)))))) |
1344 (widget-apply field :notify field))) | 1321 (widget-apply field :notify field))) |
1345 (error (debug "After Change")))) | 1322 (error (debug "After Change")))) |
1346 | 1323 |
1324 | |
1347 ;;; Widget Functions | 1325 ;;; Widget Functions |
1348 ;; | 1326 ;; |
1349 ;; These functions are used in the definition of multiple widgets. | 1327 ;; These functions are used in the definition of multiple widgets. |
1350 | 1328 |
1351 (defun widget-parent-action (widget &optional event) | 1329 (defun widget-parent-action (widget &optional event) |
1353 Optional EVENT is the event that triggered the action." | 1331 Optional EVENT is the event that triggered the action." |
1354 (widget-apply (widget-get widget :parent) :action event)) | 1332 (widget-apply (widget-get widget :parent) :action event)) |
1355 | 1333 |
1356 (defun widget-children-value-delete (widget) | 1334 (defun widget-children-value-delete (widget) |
1357 "Delete all :children and :buttons in WIDGET." | 1335 "Delete all :children and :buttons in WIDGET." |
1358 (mapcar 'widget-delete (widget-get widget :children)) | 1336 (mapc 'widget-delete (widget-get widget :children)) |
1359 (widget-put widget :children nil) | 1337 (widget-put widget :children nil) |
1360 (mapcar 'widget-delete (widget-get widget :buttons)) | 1338 (mapc 'widget-delete (widget-get widget :buttons)) |
1361 (widget-put widget :buttons nil)) | 1339 (widget-put widget :buttons nil)) |
1362 | 1340 |
1363 (defun widget-children-validate (widget) | 1341 (defun widget-children-validate (widget) |
1364 "All the :children must be valid." | 1342 "All the :children must be valid." |
1365 (let ((children (widget-get widget :children)) | 1343 (let ((children (widget-get widget :children)) |
1451 ((eq escape ?\}) | 1429 ((eq escape ?\}) |
1452 (setq sample-end (point))) | 1430 (setq sample-end (point))) |
1453 ((eq escape ?n) | 1431 ((eq escape ?n) |
1454 (when (widget-get widget :indent) | 1432 (when (widget-get widget :indent) |
1455 (insert "\n") | 1433 (insert "\n") |
1456 (insert-char ? (widget-get widget :indent)))) | 1434 (insert-char ?\ (widget-get widget :indent)))) |
1457 ((eq escape ?t) | 1435 ((eq escape ?t) |
1458 (let ((glyph (widget-get widget :tag-glyph)) | 1436 (let ((glyph (widget-get widget :tag-glyph)) |
1459 (tag (widget-get widget :tag))) | 1437 (tag (widget-get widget :tag))) |
1460 (cond (glyph | 1438 (cond (glyph |
1461 (widget-glyph-insert widget (or tag "image") glyph)) | 1439 (widget-glyph-insert widget (or tag "image") glyph)) |
1475 (setq doc-end (point))))) | 1453 (setq doc-end (point))))) |
1476 ((eq escape ?v) | 1454 ((eq escape ?v) |
1477 (if (and button-begin (not button-end)) | 1455 (if (and button-begin (not button-end)) |
1478 (widget-apply widget :value-create) | 1456 (widget-apply widget :value-create) |
1479 (setq value-pos (point)))) | 1457 (setq value-pos (point)))) |
1480 (t | 1458 (t |
1481 (widget-apply widget :format-handler escape))))) | 1459 (widget-apply widget :format-handler escape))))) |
1482 ;; Specify button, sample, and doc, and insert value. | 1460 ;; Specify button, sample, and doc, and insert value. |
1483 (and button-begin button-end | 1461 (and button-begin button-end |
1484 (widget-specify-button widget button-begin button-end)) | 1462 (widget-specify-button widget button-begin button-end)) |
1485 (and sample-begin sample-end | 1463 (and sample-begin sample-end |
1551 | 1529 |
1552 (defun widget-default-delete (widget) | 1530 (defun widget-default-delete (widget) |
1553 ;; Remove widget from the buffer. | 1531 ;; Remove widget from the buffer. |
1554 (let ((from (widget-get widget :from)) | 1532 (let ((from (widget-get widget :from)) |
1555 (to (widget-get widget :to)) | 1533 (to (widget-get widget :to)) |
1556 (inactive-overlay (widget-get widget :inactive)) | 1534 (inactive-extent (widget-get widget :inactive)) |
1557 (button-overlay (widget-get widget :button-overlay)) | 1535 (button-extent (widget-get widget :button-extent)) |
1558 (sample-overlay (widget-get widget :sample-overlay)) | 1536 (sample-extent (widget-get widget :sample-extent)) |
1559 (doc-overlay (widget-get widget :doc-overlay)) | 1537 (doc-extent (widget-get widget :doc-extent)) |
1560 before-change-functions | 1538 before-change-functions |
1561 after-change-functions | 1539 after-change-functions |
1562 (inhibit-read-only t)) | 1540 (inhibit-read-only t)) |
1563 (widget-apply widget :value-delete) | 1541 (widget-apply widget :value-delete) |
1564 (when inactive-overlay | 1542 (when inactive-extent |
1565 (delete-overlay inactive-overlay)) | 1543 (detach-extent inactive-extent)) |
1566 (when button-overlay | 1544 (when button-extent |
1567 (delete-overlay button-overlay)) | 1545 (detach-extent button-extent)) |
1568 (when sample-overlay | 1546 (when sample-extent |
1569 (delete-overlay sample-overlay)) | 1547 (detach-extent sample-extent)) |
1570 (when doc-overlay | 1548 (when doc-extent |
1571 (delete-overlay doc-overlay)) | 1549 (detach-extent doc-extent)) |
1572 (when (< from to) | 1550 (when (< from to) |
1573 ;; Kludge: this doesn't need to be true for empty formats. | 1551 ;; Kludge: this doesn't need to be true for empty formats. |
1574 (delete-region from to)) | 1552 (delete-region from to)) |
1575 (set-marker from nil) | 1553 (set-marker from nil) |
1576 (set-marker to nil)) | 1554 (set-marker to nil)) |
1688 ;; Just notify itself. | 1666 ;; Just notify itself. |
1689 (widget-apply widget :notify widget event)) | 1667 (widget-apply widget :notify widget event)) |
1690 | 1668 |
1691 ;;; The `push-button' Widget. | 1669 ;;; The `push-button' Widget. |
1692 | 1670 |
1693 (defcustom widget-push-button-gui t | 1671 (defcustom widget-push-button-gui widget-glyph-enable |
1694 "If non nil, use GUI push buttons when available." | 1672 "If non nil, use GUI push buttons when available." |
1695 :group 'widgets | 1673 :group 'widgets |
1696 :type 'boolean) | 1674 :type 'boolean) |
1697 | 1675 |
1698 ;; Cache already created GUI objects. | 1676 ;; Cache already created GUI objects. |
1720 (let* ((tag (or (widget-get widget :tag) | 1698 (let* ((tag (or (widget-get widget :tag) |
1721 (widget-get widget :value))) | 1699 (widget-get widget :value))) |
1722 (tag-glyph (widget-get widget :tag-glyph)) | 1700 (tag-glyph (widget-get widget :tag-glyph)) |
1723 (text (concat widget-push-button-prefix | 1701 (text (concat widget-push-button-prefix |
1724 tag widget-push-button-suffix)) | 1702 tag widget-push-button-suffix)) |
1725 (gui (cdr (assoc tag widget-push-button-cache)))) | 1703 (gui-glyphs (lax-plist-get widget-push-button-cache tag))) |
1726 (cond (tag-glyph | 1704 (cond (tag-glyph |
1727 (widget-glyph-insert widget text tag-glyph)) | 1705 (widget-glyph-insert widget text tag-glyph)) |
1728 ((and (fboundp 'make-gui-button) | 1706 ;; We must check for console-on-window-system-p here, |
1729 (fboundp 'make-glyph) | 1707 ;; because GUI will not work otherwise (it needs RGB |
1730 widget-push-button-gui | 1708 ;; components for colors, and they are not known on TTYs). |
1731 (fboundp 'device-on-window-system-p) | 1709 ((and widget-push-button-gui |
1732 (device-on-window-system-p) | 1710 (console-on-window-system-p)) |
1733 (string-match "XEmacs" emacs-version)) | 1711 (unless gui-glyphs |
1734 (unless gui | 1712 (let ((gui (make-gui-button tag 'widget-gui-action widget))) |
1735 (setq gui (make-gui-button tag 'widget-gui-action widget)) | 1713 (setq |
1736 (push (cons tag gui) widget-push-button-cache)) | 1714 gui-glyphs |
1737 (widget-glyph-insert-glyph widget | 1715 (list |
1738 (make-glyph | 1716 (make-glyph `(,(nth 0 (aref gui 1)) [string :data ,text])) |
1739 (list (nth 0 (aref gui 1)) | 1717 (make-glyph `(,(nth 1 (aref gui 1)) [string :data ,text])) |
1740 (vector 'string ':data text))) | 1718 (make-glyph `(,(nth 2 (aref gui 1)) [string :data ,text])))) |
1741 (make-glyph | 1719 (setq widget-push-button-cache |
1742 (list (nth 1 (aref gui 1)) | 1720 (lax-plist-put widget-push-button-cache tag gui-glyphs)))) |
1743 (vector 'string ':data text))) | 1721 (widget-glyph-insert-glyph |
1744 (make-glyph | 1722 widget (nth 0 gui-glyphs) (nth 1 gui-glyphs) (nth 2 gui-glyphs))) |
1745 (list (nth 2 (aref gui 1)) | |
1746 (vector 'string ':data text))))) | |
1747 (t | 1723 (t |
1748 (insert text))))) | 1724 (insert text))))) |
1749 | 1725 |
1750 (defun widget-gui-action (widget) | 1726 (defun widget-gui-action (widget) |
1751 "Apply :action for WIDGET." | 1727 "Apply :action for WIDGET." |
1772 | 1748 |
1773 ;;; The `info-link' Widget. | 1749 ;;; The `info-link' Widget. |
1774 | 1750 |
1775 (define-widget 'info-link 'link | 1751 (define-widget 'info-link 'link |
1776 "A link to an info file." | 1752 "A link to an info file." |
1753 :help-echo 'widget-info-link-help-echo | |
1777 :action 'widget-info-link-action) | 1754 :action 'widget-info-link-action) |
1755 | |
1756 (defun widget-info-link-help-echo (widget) | |
1757 (concat "Read the manual entry `" (widget-value widget) "'")) | |
1778 | 1758 |
1779 (defun widget-info-link-action (widget &optional event) | 1759 (defun widget-info-link-action (widget &optional event) |
1780 "Open the info node specified by WIDGET." | 1760 "Open the info node specified by WIDGET." |
1781 (Info-goto-node (widget-value widget))) | 1761 (Info-goto-node (widget-value widget))) |
1782 | 1762 |
1783 ;;; The `url-link' Widget. | 1763 ;;; The `url-link' Widget. |
1784 | 1764 |
1785 (define-widget 'url-link 'link | 1765 (define-widget 'url-link 'link |
1786 "A link to an www page." | 1766 "A link to an www page." |
1767 :help-echo 'widget-url-link-help-echo | |
1787 :action 'widget-url-link-action) | 1768 :action 'widget-url-link-action) |
1769 | |
1770 (defun widget-url-link-help-echo (widget) | |
1771 (concat "Go to <URL:" (widget-value widget) ">")) | |
1788 | 1772 |
1789 (defun widget-url-link-action (widget &optional event) | 1773 (defun widget-url-link-action (widget &optional event) |
1790 "Open the url specified by WIDGET." | 1774 "Open the url specified by WIDGET." |
1791 (require 'browse-url) | 1775 (require 'browse-url) |
1792 (funcall browse-url-browser-function (widget-value widget))) | 1776 (funcall browse-url-browser-function (widget-value widget))) |
1803 | 1787 |
1804 ;;; The `emacs-library-link' Widget. | 1788 ;;; The `emacs-library-link' Widget. |
1805 | 1789 |
1806 (define-widget 'emacs-library-link 'link | 1790 (define-widget 'emacs-library-link 'link |
1807 "A link to an Emacs Lisp library file." | 1791 "A link to an Emacs Lisp library file." |
1792 :help-echo 'widget-emacs-library-link-help-echo | |
1808 :action 'widget-emacs-library-link-action) | 1793 :action 'widget-emacs-library-link-action) |
1794 | |
1795 (defun widget-emacs-library-link-help-echo (widget) | |
1796 (concat "Visit " (widget-value widget))) | |
1809 | 1797 |
1810 (defun widget-emacs-library-link-action (widget &optional event) | 1798 (defun widget-emacs-library-link-action (widget &optional event) |
1811 "Find the Emacs Library file specified by WIDGET." | 1799 "Find the Emacs Library file specified by WIDGET." |
1812 (find-file (locate-library (widget-value widget)))) | 1800 (find-file (locate-library (widget-value widget)))) |
1813 | 1801 |
1814 ;;; The `emacs-commentary-link' Widget. | 1802 ;;; The `emacs-commentary-link' Widget. |
1815 | 1803 |
1816 (define-widget 'emacs-commentary-link 'link | 1804 (define-widget 'emacs-commentary-link 'link |
1817 "A link to Commentary in an Emacs Lisp library file." | 1805 "A link to Commentary in an Emacs Lisp library file." |
1818 :action 'widget-emacs-commentary-link-action) | 1806 :action 'widget-emacs-commentary-link-action) |
1819 | 1807 |
1820 (defun widget-emacs-commentary-link-action (widget &optional event) | 1808 (defun widget-emacs-commentary-link-action (widget &optional event) |
1821 "Find the Commentary section of the Emacs file specified by WIDGET." | 1809 "Find the Commentary section of the Emacs file specified by WIDGET." |
1822 (finder-commentary (widget-value widget))) | 1810 (finder-commentary (widget-value widget))) |
1823 | 1811 |
1824 ;;; The `editable-field' Widget. | 1812 ;;; The `editable-field' Widget. |
1843 | 1831 |
1844 (defvar widget-field-history nil | 1832 (defvar widget-field-history nil |
1845 "History of field minibuffer edits.") | 1833 "History of field minibuffer edits.") |
1846 | 1834 |
1847 (defun widget-field-prompt-internal (widget prompt initial history) | 1835 (defun widget-field-prompt-internal (widget prompt initial history) |
1848 ;; Read string for WIDGET promptinhg with PROMPT. | 1836 ;; Read string for WIDGET prompting with PROMPT. |
1849 ;; INITIAL is the initial input and HISTORY is a symbol containing | 1837 ;; INITIAL is the initial input and HISTORY is a symbol containing |
1850 ;; the earlier input. | 1838 ;; the earlier input. |
1851 (read-string prompt initial history)) | 1839 (read-string prompt initial history)) |
1852 | 1840 |
1853 (defun widget-field-prompt-value (widget prompt value unbound) | 1841 (defun widget-field-prompt-value (widget prompt value unbound) |
1862 (widget-apply widget :value-to-external answer)))) | 1850 (widget-apply widget :value-to-external answer)))) |
1863 | 1851 |
1864 (defvar widget-edit-functions nil) | 1852 (defvar widget-edit-functions nil) |
1865 | 1853 |
1866 (defun widget-field-action (widget &optional event) | 1854 (defun widget-field-action (widget &optional event) |
1867 ;; Move to next field. | 1855 ;; Edit the value in the minibuffer. |
1868 (widget-forward 1) | 1856 (let ((invalid (widget-apply widget :validate))) |
1857 (let ((prompt (concat (widget-apply widget :menu-tag-get) ": ")) | |
1858 (value (unless invalid | |
1859 (widget-value widget)))) | |
1860 (let ((answer (widget-apply widget :prompt-value prompt value invalid))) | |
1861 (widget-value-set widget answer))) | |
1862 (widget-apply widget :notify widget event) | |
1863 (widget-setup)) | |
1869 (run-hook-with-args 'widget-edit-functions widget)) | 1864 (run-hook-with-args 'widget-edit-functions widget)) |
1865 | |
1866 ;(defun widget-field-action (widget &optional event) | |
1867 ; ;; Move to next field. | |
1868 ; (widget-forward 1) | |
1869 ; (run-hook-with-args 'widget-edit-functions widget)) | |
1870 | 1870 |
1871 (defun widget-field-validate (widget) | 1871 (defun widget-field-validate (widget) |
1872 ;; Valid if the content matches `:valid-regexp'. | 1872 ;; Valid if the content matches `:valid-regexp'. |
1873 (save-excursion | 1873 (save-excursion |
1874 (let ((value (widget-apply widget :value-get)) | 1874 (let ((value (widget-apply widget :value-get)) |
1880 (defun widget-field-value-create (widget) | 1880 (defun widget-field-value-create (widget) |
1881 ;; Create an editable text field. | 1881 ;; Create an editable text field. |
1882 (let ((size (widget-get widget :size)) | 1882 (let ((size (widget-get widget :size)) |
1883 (value (widget-get widget :value)) | 1883 (value (widget-get widget :value)) |
1884 (from (point)) | 1884 (from (point)) |
1885 ;; This is changed to a real overlay in `widget-setup'. We | 1885 ;; This used to make `field-overlay' a cons of two markers, |
1886 ;; need the end points to behave differently until | 1886 ;; and revert them to a real overlay in `widget-setup', |
1887 ;; `widget-setup' is called. | 1887 ;; because you can't change overlay insertion type. However, |
1888 (overlay (cons (make-marker) (make-marker)))) | 1888 ;; we can do that with extents. |
1889 (widget-put widget :field-overlay overlay) | 1889 extent) |
1890 (insert value) | 1890 (insert value) |
1891 (and size | 1891 (and size |
1892 (< (length value) size) | 1892 (< (length value) size) |
1893 (insert-char ?\ (- size (length value)))) | 1893 (insert-char ?\ (- size (length value)))) |
1894 (unless (memq widget widget-field-list) | 1894 (unless (memq widget widget-field-list) |
1895 (setq widget-field-new (cons widget widget-field-new))) | 1895 (push widget widget-field-new)) |
1896 (move-marker (cdr overlay) (point)) | 1896 (setq extent (make-extent from (point))) |
1897 (set-marker-insertion-type (cdr overlay) nil) | 1897 (set-extent-property extent 'end-open t) |
1898 (widget-put widget :field-extent extent) | |
1898 (when (null size) | 1899 (when (null size) |
1899 (insert ?\n)) | 1900 (insert ?\n)) |
1900 (move-marker (car overlay) from) | 1901 (set-extent-property extent 'start-open t))) |
1901 (set-marker-insertion-type (car overlay) t))) | |
1902 | 1902 |
1903 (defun widget-field-value-delete (widget) | 1903 (defun widget-field-value-delete (widget) |
1904 ;; Remove the widget from the list of active editing fields. | 1904 ;; Remove the widget from the list of active editing fields. |
1905 (setq widget-field-list (delq widget widget-field-list)) | 1905 (setq widget-field-list (delq widget widget-field-list)) |
1906 ;; These are nil if the :format string doesn't contain `%v'. | 1906 ;; These are nil if the :format string doesn't contain `%v'. |
1907 (let ((overlay (widget-get widget :field-overlay))) | 1907 (let ((extent (widget-get widget :field-extent))) |
1908 (when overlay | 1908 (when extent |
1909 (delete-overlay overlay)))) | 1909 (detach-extent extent)))) |
1910 | 1910 |
1911 (defun widget-field-value-get (widget) | 1911 (defun widget-field-value-get (widget) |
1912 ;; Return current text in editing field. | 1912 ;; Return current text in editing field. |
1913 (let ((from (widget-field-start widget)) | 1913 (let ((from (widget-field-start widget)) |
1914 (to (widget-field-end widget)) | 1914 (to (widget-field-end widget)) |
1915 (buffer (widget-field-buffer widget)) | 1915 (buffer (widget-field-buffer widget)) |
1916 (size (widget-get widget :size)) | 1916 (size (widget-get widget :size)) |
1917 (secret (widget-get widget :secret)) | 1917 (secret (widget-get widget :secret)) |
1918 (old (current-buffer))) | 1918 (old (current-buffer))) |
1919 (if (and from to) | 1919 (if (and from to) |
1920 (progn | 1920 (progn |
1921 (set-buffer buffer) | 1921 (set-buffer buffer) |
1922 (while (and size | 1922 (while (and size |
1923 (not (zerop size)) | 1923 (not (zerop size)) |
1924 (> to from) | 1924 (> to from) |
1925 (eq (char-after (1- to)) ?\ )) | 1925 (eq (char-after (1- to)) ?\ )) |
1928 (when secret | 1928 (when secret |
1929 (let ((index 0)) | 1929 (let ((index 0)) |
1930 (while (< (+ from index) to) | 1930 (while (< (+ from index) to) |
1931 (aset result index | 1931 (aset result index |
1932 (get-char-property (+ from index) 'secret)) | 1932 (get-char-property (+ from index) 'secret)) |
1933 (setq index (1+ index))))) | 1933 (incf index)))) |
1934 (set-buffer old) | 1934 (set-buffer old) |
1935 result)) | 1935 result)) |
1936 (widget-get widget :value)))) | 1936 (widget-get widget :value)))) |
1937 | 1937 |
1938 (defun widget-field-match (widget value) | 1938 (defun widget-field-match (widget value) |
2002 | 2002 |
2003 (defun widget-choice-mouse-down-action (widget &optional event) | 2003 (defun widget-choice-mouse-down-action (widget &optional event) |
2004 ;; Return non-nil if we need a menu. | 2004 ;; Return non-nil if we need a menu. |
2005 (let ((args (widget-get widget :args)) | 2005 (let ((args (widget-get widget :args)) |
2006 (old (widget-get widget :choice))) | 2006 (old (widget-get widget :choice))) |
2007 (cond ((not window-system) | 2007 (cond ((not (console-on-window-system-p)) |
2008 ;; No place to pop up a menu. | 2008 ;; No place to pop up a menu. |
2009 nil) | |
2010 ((not (or (fboundp 'x-popup-menu) (fboundp 'popup-menu))) | |
2011 ;; No way to pop up a menu. | |
2012 nil) | 2009 nil) |
2013 ((< (length args) 2) | 2010 ((< (length args) 2) |
2014 ;; Empty or singleton list, just return the value. | 2011 ;; Empty or singleton list, just return the value. |
2015 nil) | 2012 nil) |
2016 ((> (length args) widget-menu-max-size) | 2013 ((> (length args) widget-menu-max-size) |
2234 values (cdr vals) | 2231 values (cdr vals) |
2235 args (delq answer args)))) | 2232 args (delq answer args)))) |
2236 (greedy | 2233 (greedy |
2237 (setq rest (append rest (list (car values))) | 2234 (setq rest (append rest (list (car values))) |
2238 values (cdr values))) | 2235 values (cdr values))) |
2239 (t | 2236 (t |
2240 (setq rest (append rest values) | 2237 (setq rest (append rest values) |
2241 values nil))))) | 2238 values nil))))) |
2242 (cons found rest))) | 2239 (cons found rest))) |
2243 | 2240 |
2244 (defun widget-checklist-match-find (widget vals) | 2241 (defun widget-checklist-match-find (widget vals) |
2584 (let ((type (nth 0 (widget-get widget :args))) | 2581 (let ((type (nth 0 (widget-get widget :args))) |
2585 (ok t) | 2582 (ok t) |
2586 found) | 2583 found) |
2587 (while (and value ok) | 2584 (while (and value ok) |
2588 (let ((answer (widget-match-inline type value))) | 2585 (let ((answer (widget-match-inline type value))) |
2589 (if answer | 2586 (if answer |
2590 (setq found (append found (car answer)) | 2587 (setq found (append found (car answer)) |
2591 value (cdr answer)) | 2588 value (cdr answer)) |
2592 (setq ok nil)))) | 2589 (setq ok nil)))) |
2593 (cons found value))) | 2590 (cons found value))) |
2594 | 2591 |
2736 argument answer found) | 2733 argument answer found) |
2737 (while args | 2734 (while args |
2738 (setq argument (car args) | 2735 (setq argument (car args) |
2739 args (cdr args) | 2736 args (cdr args) |
2740 answer (widget-match-inline argument vals)) | 2737 answer (widget-match-inline argument vals)) |
2741 (if answer | 2738 (if answer |
2742 (setq vals (cdr answer) | 2739 (setq vals (cdr answer) |
2743 found (append found (car answer))) | 2740 found (append found (car answer))) |
2744 (setq vals nil | 2741 (setq vals nil |
2745 args nil))) | 2742 args nil))) |
2746 (if answer | 2743 (if answer |
2875 buttons) | 2872 buttons) |
2876 (insert before " ") | 2873 (insert before " ") |
2877 (widget-documentation-link-add widget start (point)) | 2874 (widget-documentation-link-add widget start (point)) |
2878 (push (widget-create-child-and-convert | 2875 (push (widget-create-child-and-convert |
2879 widget 'visibility | 2876 widget 'visibility |
2880 :help-echo "Show or hide rest of the documentation." | 2877 :help-echo (lambda (widget) |
2878 ;; This can get called directly from | |
2879 ;; default-mouse-motion-handler, with an | |
2880 ;; extent argument. | |
2881 (and (extentp widget) | |
2882 (setq | |
2883 widget (widget-at | |
2884 (extent-start-position widget)))) | |
2885 (concat | |
2886 (if (widget-value widget) | |
2887 "Hide" "Show") | |
2888 " the rest of the documentation.")) | |
2881 :off "More" | 2889 :off "More" |
2882 :action 'widget-parent-action | 2890 :action 'widget-parent-action |
2883 shown) | 2891 shown) |
2884 buttons) | 2892 buttons) |
2885 (when shown | 2893 (when shown |
3078 "A lisp variable." | 3086 "A lisp variable." |
3079 :prompt-match 'boundp | 3087 :prompt-match 'boundp |
3080 :prompt-history 'widget-variable-prompt-value-history | 3088 :prompt-history 'widget-variable-prompt-value-history |
3081 :tag "Variable") | 3089 :tag "Variable") |
3082 | 3090 |
3083 (when (featurep 'mule) | 3091 ;; This part issues a warning when compiling without Mule. Is there a |
3084 (defvar widget-coding-system-prompt-value-history nil | 3092 ;; way of shutting it up? |
3085 "History of input to `widget-coding-system-prompt-value'.") | 3093 ;; |
3086 | 3094 ;; OK, I'll simply comment the whole thing out, until someone decides |
3087 (define-widget 'coding-system 'symbol | 3095 ;; to do something with it. |
3088 "A MULE coding-system." | 3096 ;(defvar widget-coding-system-prompt-value-history nil |
3089 :format "%{%t%}: %v" | 3097 ; "History of input to `widget-coding-system-prompt-value'.") |
3090 :tag "Coding system" | 3098 |
3091 :prompt-history 'widget-coding-system-prompt-value-history | 3099 ;(define-widget 'coding-system 'symbol |
3092 :prompt-value 'widget-coding-system-prompt-value | 3100 ; "A MULE coding-system." |
3093 :action 'widget-coding-system-action) | 3101 ; :format "%{%t%}: %v" |
3094 | 3102 ; :tag "Coding system" |
3095 (defun widget-coding-system-prompt-value (widget prompt value unbound) | 3103 ; :prompt-history 'widget-coding-system-prompt-value-history |
3096 ;; Read coding-system from minibuffer. | 3104 ; :prompt-value 'widget-coding-system-prompt-value |
3097 (intern | 3105 ; :action 'widget-coding-system-action) |
3098 (completing-read (format "%s (default %s) " prompt value) | 3106 |
3099 (mapcar (function | 3107 ;(defun widget-coding-system-prompt-value (widget prompt value unbound) |
3100 (lambda (sym) | 3108 ; ;; Read coding-system from minibuffer. |
3101 (list (symbol-name sym)) | 3109 ; (intern |
3102 )) | 3110 ; (completing-read (format "%s (default %s) " prompt value) |
3103 (coding-system-list))))) | 3111 ; (mapcar (lambda (sym) |
3104 | 3112 ; (list (symbol-name sym))) |
3105 (defun widget-coding-system-action (widget &optional event) | 3113 ; (coding-system-list))))) |
3106 ;; Read a file name from the minibuffer. | 3114 |
3107 (let ((answer | 3115 ;(defun widget-coding-system-action (widget &optional event) |
3108 (widget-coding-system-prompt-value | 3116 ; ;; Read a file name from the minibuffer. |
3109 widget | 3117 ; (let ((answer |
3110 (widget-apply widget :menu-tag-get) | 3118 ; (widget-coding-system-prompt-value |
3111 (widget-value widget) | 3119 ; widget |
3112 t))) | 3120 ; (widget-apply widget :menu-tag-get) |
3113 (widget-value-set widget answer) | 3121 ; (widget-value widget) |
3114 (widget-apply widget :notify widget event) | 3122 ; t))) |
3115 (widget-setup))) | 3123 ; (widget-value-set widget answer) |
3116 ) | 3124 ; (widget-apply widget :notify widget event) |
3125 ; (widget-setup))) | |
3117 | 3126 |
3118 (define-widget 'sexp 'editable-field | 3127 (define-widget 'sexp 'editable-field |
3119 "An arbitrary lisp expression." | 3128 "An arbitrary lisp expression." |
3120 :tag "Lisp expression" | 3129 :tag "Lisp expression" |
3121 :format "%{%t%}: %v" | 3130 :format "%{%t%}: %v" |
3232 :value-to-external (lambda (widget value) | 3241 :value-to-external (lambda (widget value) |
3233 (if (stringp value) | 3242 (if (stringp value) |
3234 (aref value 0) | 3243 (aref value 0) |
3235 value)) | 3244 value)) |
3236 :match (lambda (widget value) | 3245 :match (lambda (widget value) |
3237 (if (fboundp 'characterp) | 3246 (characterp value))) |
3238 (characterp value) | |
3239 (integerp value)))) | |
3240 | 3247 |
3241 (define-widget 'list 'group | 3248 (define-widget 'list 'group |
3242 "A lisp list." | 3249 "A lisp list." |
3243 :tag "List" | 3250 :tag "List" |
3244 :format "%{%t%}:\n%v") | 3251 :format "%{%t%}:\n%v") |
3369 (let* ((prefix (buffer-substring-no-properties (widget-field-start widget) | 3376 (let* ((prefix (buffer-substring-no-properties (widget-field-start widget) |
3370 (point))) | 3377 (point))) |
3371 (list (widget-color-choice-list)) | 3378 (list (widget-color-choice-list)) |
3372 (completion (try-completion prefix list))) | 3379 (completion (try-completion prefix list))) |
3373 (cond ((eq completion t) | 3380 (cond ((eq completion t) |
3374 (message "Exact match.")) | 3381 (message "Exact match")) |
3375 ((null completion) | 3382 ((null completion) |
3376 (error "Can't find completion for \"%s\"" prefix)) | 3383 (error "Can't find completion for \"%s\"" prefix)) |
3377 ((not (string-equal prefix completion)) | 3384 ((not (string-equal prefix completion)) |
3378 (insert-and-inherit (substring completion (length prefix)))) | 3385 (insert-and-inherit (substring completion (length prefix)))) |
3379 (t | 3386 (t |
3386 (defun widget-color-sample-face-get (widget) | 3393 (defun widget-color-sample-face-get (widget) |
3387 (let* ((value (condition-case nil | 3394 (let* ((value (condition-case nil |
3388 (widget-value widget) | 3395 (widget-value widget) |
3389 (error (widget-get widget :value)))) | 3396 (error (widget-get widget :value)))) |
3390 (symbol (intern (concat "fg:" value)))) | 3397 (symbol (intern (concat "fg:" value)))) |
3391 (if (string-match "XEmacs" emacs-version) | 3398 (prog1 symbol |
3392 (prog1 symbol | 3399 (or (find-face symbol) |
3393 (or (find-face symbol) | 3400 (set-face-foreground (make-face symbol) value))))) |
3394 (set-face-foreground (make-face symbol) value))) | |
3395 (condition-case nil | |
3396 (facemenu-get-face symbol) | |
3397 (error 'default))))) | |
3398 | 3401 |
3399 (defvar widget-color-choice-list nil) | 3402 (defvar widget-color-choice-list nil) |
3400 ;; Variable holding the possible colors. | 3403 ;; Variable holding the possible colors. |
3401 | 3404 |
3402 (defun widget-color-choice-list () | 3405 (defun widget-color-choice-list () |
3403 (unless widget-color-choice-list | 3406 (or widget-color-choice-list |
3404 (setq widget-color-choice-list | 3407 (setq widget-color-choice-list (read-color-completion-table)))) |
3405 (if (fboundp 'read-color-completion-table) | |
3406 (read-color-completion-table) | |
3407 (mapcar '(lambda (color) (list color)) | |
3408 (x-defined-colors))))) | |
3409 widget-color-choice-list) | |
3410 | 3408 |
3411 (defvar widget-color-history nil | 3409 (defvar widget-color-history nil |
3412 "History of entered colors") | 3410 "History of entered colors") |
3413 | 3411 |
3414 (defun widget-color-action (widget &optional event) | 3412 (defun widget-color-action (widget &optional event) |
3434 (widget-value-set widget answer) | 3432 (widget-value-set widget answer) |
3435 (widget-setup) | 3433 (widget-setup) |
3436 (widget-apply widget :notify widget event)))) | 3434 (widget-apply widget :notify widget event)))) |
3437 | 3435 |
3438 (defun widget-color-notify (widget child &optional event) | 3436 (defun widget-color-notify (widget child &optional event) |
3439 "Update the sample, and notofy the parent." | 3437 "Update the sample, and notify the parent." |
3440 (overlay-put (widget-get widget :sample-overlay) | 3438 (set-extent-property (widget-get widget :sample-extent) |
3441 'face (widget-apply widget :sample-face-get)) | 3439 'face (widget-apply widget :sample-face-get)) |
3442 (widget-default-notify widget child event)) | 3440 (widget-default-notify widget child event)) |
3443 | |
3444 ;;; The Help Echo | |
3445 | |
3446 (defun widget-echo-help-mouse () | |
3447 "Display the help message for the widget under the mouse. | |
3448 Enable with (run-with-idle-timer 1 t 'widget-echo-help-mouse)" | |
3449 (let* ((pos (mouse-position)) | |
3450 (frame (car pos)) | |
3451 (x (car (cdr pos))) | |
3452 (y (cdr (cdr pos))) | |
3453 (win (window-at x y frame)) | |
3454 (where (coordinates-in-window-p (cons x y) win))) | |
3455 (when (consp where) | |
3456 (save-window-excursion | |
3457 (progn ; save-excursion | |
3458 (select-window win) | |
3459 (let* ((result (compute-motion (window-start win) | |
3460 '(0 . 0) | |
3461 (window-end win) | |
3462 where | |
3463 (window-width win) | |
3464 (cons (window-hscroll) 0) | |
3465 win))) | |
3466 (when (and (eq (nth 1 result) x) | |
3467 (eq (nth 2 result) y)) | |
3468 (widget-echo-help (nth 0 result)))))))) | |
3469 (unless track-mouse | |
3470 (setq track-mouse t) | |
3471 (add-hook 'post-command-hook 'widget-stop-mouse-tracking))) | |
3472 | |
3473 (defun widget-stop-mouse-tracking (&rest args) | |
3474 "Stop the mouse tracking done while idle." | |
3475 (remove-hook 'post-command-hook 'widget-stop-mouse-tracking) | |
3476 (setq track-mouse nil)) | |
3477 | 3441 |
3478 (defun widget-at (pos) | 3442 (defun widget-at (pos) |
3479 "The button or field at POS." | 3443 "The button or field at POS." |
3480 (or (get-char-property pos 'button) | 3444 (or (get-char-property pos 'button) |
3481 (get-char-property pos 'field))) | 3445 (get-char-property pos 'field))) |
3484 "Display the help echo for widget at POS." | 3448 "Display the help echo for widget at POS." |
3485 (let* ((widget (widget-at pos)) | 3449 (let* ((widget (widget-at pos)) |
3486 (help-echo (and widget (widget-get widget :help-echo)))) | 3450 (help-echo (and widget (widget-get widget :help-echo)))) |
3487 (cond ((stringp help-echo) | 3451 (cond ((stringp help-echo) |
3488 (message "%s" help-echo)) | 3452 (message "%s" help-echo)) |
3489 ((and (symbolp help-echo) (fboundp help-echo) | 3453 ((and (functionp help-echo) |
3490 (stringp (setq help-echo (funcall help-echo widget)))) | 3454 (stringp (setq help-echo (funcall help-echo widget)))) |
3491 (message "%s" help-echo))))) | 3455 (message "%s" help-echo))))) |
3492 | 3456 |
3493 ;;; The End: | 3457 ;;; The End: |
3494 | 3458 |