Mercurial > hg > xemacs-beta
comparison lisp/custom/wid-edit.el @ 173:8eaf7971accc r20-3b13
Import from CVS: tag r20-3b13
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:49:09 +0200 |
parents | 85ec50267440 |
children | 9ad43877534d |
comparison
equal
deleted
inserted
replaced
172:a38aed19690b | 173:8eaf7971accc |
---|---|
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 ;; Keywords: extensions | 6 ;; Keywords: extensions |
7 ;; Version: 1.9940 | 7 ;; Version: 1.9951 |
8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ | 8 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/ |
9 | 9 |
10 ;; This file is part of GNU Emacs. | 10 ;; This file is part of GNU Emacs. |
11 | 11 |
12 ;; GNU Emacs is free software; you can redistribute it and/or modify | 12 ;; GNU Emacs is free software; you can redistribute it and/or modify |
36 ;;; Compatibility. | 36 ;;; Compatibility. |
37 | 37 |
38 (eval-and-compile | 38 (eval-and-compile |
39 (autoload 'pp-to-string "pp") | 39 (autoload 'pp-to-string "pp") |
40 (autoload 'Info-goto-node "info") | 40 (autoload 'Info-goto-node "info") |
41 (autoload 'finder-commentary "finder" nil t) | |
41 | 42 |
42 (when (string-match "XEmacs" emacs-version) | 43 (when (string-match "XEmacs" emacs-version) |
43 (condition-case nil | 44 (condition-case nil |
44 (require 'overlay) | 45 (require 'overlay) |
45 (error (load-library "x-overlay")))) | 46 (error (load-library "x-overlay")))) |
99 (let ((buf (get-buffer-create " *error-message*"))) | 100 (let ((buf (get-buffer-create " *error-message*"))) |
100 (erase-buffer buf) | 101 (erase-buffer buf) |
101 (display-error obj buf) | 102 (display-error obj buf) |
102 (buffer-string buf))))) | 103 (buffer-string buf))))) |
103 | 104 |
104 (when (let ((a "foo")) | |
105 (put-text-property 1 2 'foo 1 a) | |
106 (put-text-property 1 2 'bar 2 a) | |
107 (set-text-properties 1 2 nil a) | |
108 (text-properties-at 1 a)) | |
109 ;; XEmacs 20.2 and earlier had a buggy set-text-properties. | |
110 (defun set-text-properties (start end props &optional buffer-or-string) | |
111 "Completely replace properties of text from START to END. | |
112 The third argument PROPS is the new property list. | |
113 The optional fourth argument, BUFFER-OR-STRING, | |
114 is the string or buffer containing the text." | |
115 (map-extents #'(lambda (extent ignored) | |
116 (remove-text-properties | |
117 start end | |
118 (list (extent-property extent 'text-prop) | |
119 nil) | |
120 buffer-or-string) | |
121 nil) | |
122 buffer-or-string start end nil nil 'text-prop) | |
123 (add-text-properties start end props buffer-or-string))) | |
124 | |
125 ;;; Customization. | 105 ;;; Customization. |
126 | 106 |
127 (defgroup widgets nil | 107 (defgroup widgets nil |
128 "Customization support for the Widget Library." | 108 "Customization support for the Widget Library." |
129 :link '(custom-manual "(widget)Top") | 109 :link '(custom-manual "(widget)Top") |
130 :link '(url-link :tag "Development Page" | 110 :link '(url-link :tag "Development Page" |
131 "http://www.dina.kvl.dk/~abraham/custom/") | 111 "http://www.dina.kvl.dk/~abraham/custom/") |
112 :link '(emacs-library-link :tag "Lisp File" "widget.el") | |
132 :prefix "widget-" | 113 :prefix "widget-" |
133 :group 'extensions | 114 :group 'extensions |
134 :group 'hypermedia) | 115 :group 'hypermedia) |
135 | 116 |
136 (defgroup widget-documentation nil | 117 (defgroup widget-documentation nil |
155 (t nil)) | 136 (t nil)) |
156 "Face used for documentation text." | 137 "Face used for documentation text." |
157 :group 'widget-documentation | 138 :group 'widget-documentation |
158 :group 'widget-faces) | 139 :group 'widget-faces) |
159 | 140 |
141 (defvar widget-button-face 'widget-button-face | |
142 "Face used for buttons in widges. | |
143 This exists as a variable so it can be set locally in certain buffers.") | |
144 | |
160 (defface widget-button-face '((t (:bold t))) | 145 (defface widget-button-face '((t (:bold t))) |
161 "Face used for widget buttons." | 146 "Face used for widget buttons." |
162 :group 'widget-faces) | 147 :group 'widget-faces) |
163 | 148 |
164 (defcustom widget-mouse-face 'highlight | 149 (defcustom widget-mouse-face 'highlight |
234 "Largest number of items allowed in a popup-menu. | 219 "Largest number of items allowed in a popup-menu. |
235 Larger menus are read through the minibuffer." | 220 Larger menus are read through the minibuffer." |
236 :group 'widgets | 221 :group 'widgets |
237 :type 'integer) | 222 :type 'integer) |
238 | 223 |
239 (defcustom widget-menu-minibuffer-flag nil | 224 (defcustom widget-menu-minibuffer-flag (string-match "XEmacs" emacs-version) |
240 "*Control how to ask for a choice from the keyboard. | 225 "*Control how to ask for a choice from the keyboard. |
241 Non-nil means use the minibuffer; | 226 Non-nil means use the minibuffer; |
242 nil means read a single character." | 227 nil means read a single character." |
243 :group 'widgets | 228 :group 'widgets |
244 :type 'boolean) | 229 :type 'boolean) |
297 map choice (next-digit ?0) | 282 map choice (next-digit ?0) |
298 value) | 283 value) |
299 ;; Define SPC as a prefix char to get to this menu. | 284 ;; Define SPC as a prefix char to get to this menu. |
300 (define-key overriding-terminal-local-map " " | 285 (define-key overriding-terminal-local-map " " |
301 (setq map (make-sparse-keymap title))) | 286 (setq map (make-sparse-keymap title))) |
302 (while items | 287 (save-excursion |
303 (setq choice (car items) items (cdr items)) | 288 (set-buffer (get-buffer-create " widget-choose")) |
304 (if (consp choice) | 289 (erase-buffer) |
305 (let* ((name (car choice)) | 290 (insert "Available choices:\n\n") |
306 (function (cdr choice)) | 291 (while items |
307 (character (aref name 0))) | 292 (setq choice (car items) items (cdr items)) |
308 ;; Pick a character for this choice; | 293 (if (consp choice) |
309 ;; avoid duplication. | 294 (let* ((name (car choice)) |
310 (when (lookup-key map (vector character)) | 295 (function (cdr choice))) |
311 (setq character (downcase character)) | 296 (insert (format "%c = %s\n" next-digit name)) |
312 (when (lookup-key map (vector character)) | 297 (define-key map (vector next-digit) function))) |
313 (setq character next-digit | 298 ;; Allocate digits to disabled alternatives |
314 next-digit (1+ next-digit)))) | 299 ;; so that the digit of a given alternative never varies. |
315 (define-key map (vector character) | 300 (setq next-digit (1+ next-digit))) |
316 (cons (format "%c = %s" character name) function))))) | 301 (insert "\nC-g = Quit")) |
317 (define-key map [?\C-g] '("Quit" . keyboard-quit)) | 302 (define-key map [?\C-g] 'keyboard-quit) |
318 (define-key map [t] 'keyboard-quit) | 303 (define-key map [t] 'keyboard-quit) |
319 (setcdr map (nreverse (cdr map))) | 304 (setcdr map (nreverse (cdr map))) |
320 ;; Unread a SPC to lead to our new menu. | 305 ;; Unread a SPC to lead to our new menu. |
321 (setq unread-command-events (cons ?\ unread-command-events)) | 306 (setq unread-command-events (cons ?\ unread-command-events)) |
322 ;; Read a char with the menu, and return the result | 307 ;; Read a char with the menu, and return the result |
323 ;; that corresponds to it. | 308 ;; that corresponds to it. |
324 (setq value | 309 (save-window-excursion |
325 (lookup-key overriding-terminal-local-map | 310 (display-buffer (get-buffer " widget-choose")) |
326 (read-key-sequence title) t)) | 311 (let ((cursor-in-echo-area t)) |
312 (setq value | |
313 (lookup-key overriding-terminal-local-map | |
314 (read-key-sequence title) t)))) | |
327 (when (eq value 'keyboard-quit) | 315 (when (eq value 'keyboard-quit) |
328 (error "Canceled")) | 316 (error "Canceled")) |
329 value)))) | 317 value)))) |
330 | 318 |
331 (defun widget-remove-if (predictate list) | 319 (defun widget-remove-if (predictate list) |
338 | 326 |
339 ;;; Widget text specifications. | 327 ;;; Widget text specifications. |
340 ;; | 328 ;; |
341 ;; These functions are for specifying text properties. | 329 ;; These functions are for specifying text properties. |
342 | 330 |
343 (defun widget-specify-none (from to) | |
344 ;; Clear all text properties between FROM and TO. | |
345 (set-text-properties from to nil)) | |
346 | |
347 (defun widget-specify-text (from to) | |
348 ;; Default properties. | |
349 (add-text-properties from to (list 'read-only t | |
350 'front-sticky t | |
351 'rear-nonsticky nil | |
352 'start-open nil | |
353 'end-open nil))) | |
354 | |
355 (defcustom widget-field-add-space | 331 (defcustom widget-field-add-space |
356 (or (< emacs-major-version 20) | 332 (or (< emacs-major-version 20) |
357 (and (eq emacs-major-version 20) | 333 (and (eq emacs-major-version 20) |
358 (< emacs-minor-version 3)) | 334 (< emacs-minor-version 3)) |
359 (not (string-match "XEmacs" emacs-version))) | 335 (not (string-match "XEmacs" emacs-version))) |
364 size field." | 340 size field." |
365 :type 'boolean | 341 :type 'boolean |
366 :group 'widgets) | 342 :group 'widgets) |
367 | 343 |
368 (defcustom widget-field-use-before-change | 344 (defcustom widget-field-use-before-change |
369 (or (> emacs-minor-version 34) | 345 (and (or (> emacs-minor-version 34) |
370 (> emacs-major-version 20) | 346 (> emacs-major-version 19)) |
371 (string-match "XEmacs" emacs-version)) | 347 (not (string-match "XEmacs" emacs-version))) |
372 "Non-nil means use `before-change-functions' to track editable fields. | 348 "Non-nil means use `before-change-functions' to track editable fields. |
373 This enables the use of undo, but doesn'f work on Emacs 19.34 and earlier. | 349 This enables the use of undo, but doesn't work on Emacs 19.34 and earlier. |
374 Using before hooks also means that the :notify function can't know the | 350 Using before hooks also means that the :notify function can't know the |
375 new value." | 351 new value." |
376 :type 'boolean | 352 :type 'boolean |
377 :group 'widgets) | 353 :group 'widgets) |
378 | 354 |
379 (defun widget-specify-field (widget from to) | 355 (defun widget-specify-field (widget from to) |
380 "Specify editable button for WIDGET between FROM and TO." | 356 "Specify editable button for WIDGET between FROM and TO." |
381 (put-text-property from to 'read-only nil) | |
382 ;; Terminating space is not part of the field, but necessary in | 357 ;; Terminating space is not part of the field, but necessary in |
383 ;; order for local-map to work. Remove next sexp if local-map works | 358 ;; order for local-map to work. Remove next sexp if local-map works |
384 ;; at the end of the overlay. | 359 ;; at the end of the overlay. |
385 (save-excursion | 360 (save-excursion |
386 (goto-char to) | 361 (goto-char to) |
387 (when widget-field-add-space | 362 (cond ((null (widget-get widget :size)) |
388 (insert-and-inherit " ")) | 363 (forward-char 1)) |
364 (widget-field-add-space | |
365 (insert-and-inherit " "))) | |
389 (setq to (point))) | 366 (setq to (point))) |
390 (if widget-field-add-space | |
391 (add-text-properties (1- to) to | |
392 '(front-sticky nil start-open t read-only to)) | |
393 (add-text-properties to (1+ to) | |
394 '(front-sticky nil start-open t read-only to))) | |
395 (add-text-properties (1- from) from | |
396 '(rear-nonsticky t end-open t read-only from)) | |
397 (let ((map (widget-get widget :keymap)) | 367 (let ((map (widget-get widget :keymap)) |
398 (face (or (widget-get widget :value-face) 'widget-field-face)) | 368 (face (or (widget-get widget :value-face) 'widget-field-face)) |
399 (help-echo (widget-get widget :help-echo)) | 369 (help-echo (widget-get widget :help-echo)) |
400 (overlay (make-overlay from to nil nil t))) | 370 (overlay (make-overlay from to nil |
371 nil (or (not widget-field-add-space) | |
372 (widget-get widget :size))))) | |
401 (unless (or (stringp help-echo) (null help-echo)) | 373 (unless (or (stringp help-echo) (null help-echo)) |
402 (setq help-echo 'widget-mouse-help)) | 374 (setq help-echo 'widget-mouse-help)) |
403 (widget-put widget :field-overlay overlay) | 375 (widget-put widget :field-overlay overlay) |
404 (overlay-put overlay 'detachable nil) | 376 (overlay-put overlay 'detachable nil) |
405 (overlay-put overlay 'field widget) | 377 (overlay-put overlay 'field widget) |
435 (t | 407 (t |
436 (format "(widget %S :help-echo %S)" widget help-echo))))) | 408 (format "(widget %S :help-echo %S)" widget help-echo))))) |
437 | 409 |
438 (defun widget-specify-sample (widget from to) | 410 (defun widget-specify-sample (widget from to) |
439 ;; Specify sample for WIDGET between FROM and TO. | 411 ;; Specify sample for WIDGET between FROM and TO. |
440 (let ((face (widget-apply widget :sample-face-get))) | 412 (let ((face (widget-apply widget :sample-face-get)) |
441 (when face | 413 (overlay (make-overlay from to nil t nil))) |
442 (add-text-properties from to (list 'start-open t | 414 (overlay-put overlay 'face face) |
443 'end-open t | 415 (widget-put widget :sample-overlay overlay))) |
444 'face face))))) | 416 |
445 (defun widget-specify-doc (widget from to) | 417 (defun widget-specify-doc (widget from to) |
446 ;; Specify documentation for WIDGET between FROM and TO. | 418 ;; Specify documentation for WIDGET between FROM and TO. |
447 (add-text-properties from to (list 'widget-doc widget | 419 (let ((overlay (make-overlay from to nil t nil))) |
448 'face widget-documentation-face))) | 420 (overlay-put overlay 'widget-doc widget) |
421 (overlay-put overlay 'face widget-documentation-face) | |
422 (widget-put widget :doc-overlay overlay))) | |
449 | 423 |
450 (defmacro widget-specify-insert (&rest form) | 424 (defmacro widget-specify-insert (&rest form) |
451 ;; Execute FORM without inheriting any text properties. | 425 ;; Execute FORM without inheriting any text properties. |
452 (` | 426 (` |
453 (save-restriction | 427 (save-restriction |
455 result | 429 result |
456 before-change-functions | 430 before-change-functions |
457 after-change-functions) | 431 after-change-functions) |
458 (insert "<>") | 432 (insert "<>") |
459 (narrow-to-region (- (point) 2) (point)) | 433 (narrow-to-region (- (point) 2) (point)) |
460 (widget-specify-none (point-min) (point-max)) | |
461 (goto-char (1+ (point-min))) | 434 (goto-char (1+ (point-min))) |
462 (setq result (progn (,@ form))) | 435 (setq result (progn (,@ form))) |
463 (delete-region (point-min) (1+ (point-min))) | 436 (delete-region (point-min) (1+ (point-min))) |
464 (delete-region (1- (point-max)) (point-max)) | 437 (delete-region (1- (point-max)) (point-max)) |
465 (goto-char (point-max)) | 438 (goto-char (point-max)) |
868 "Call `insert' with ARGS and make the text read only." | 841 "Call `insert' with ARGS and make the text read only." |
869 (let ((inhibit-read-only t) | 842 (let ((inhibit-read-only t) |
870 before-change-functions | 843 before-change-functions |
871 after-change-functions | 844 after-change-functions |
872 (from (point))) | 845 (from (point))) |
873 (apply 'insert args) | 846 (apply 'insert args))) |
874 (widget-specify-text from (point)))) | |
875 | 847 |
876 (defun widget-convert-text (type from to | 848 (defun widget-convert-text (type from to |
877 &optional button-from button-to | 849 &optional button-from button-to |
878 &rest args) | 850 &rest args) |
879 "Return a widget of type TYPE with endpoint FROM TO. | 851 "Return a widget of type TYPE with endpoint FROM TO. |
883 button end points. | 855 button end points. |
884 Optional ARGS are extra keyword arguments for TYPE." | 856 Optional ARGS are extra keyword arguments for TYPE." |
885 (let ((widget (apply 'widget-convert type :delete 'widget-leave-text args)) | 857 (let ((widget (apply 'widget-convert type :delete 'widget-leave-text args)) |
886 (from (copy-marker from)) | 858 (from (copy-marker from)) |
887 (to (copy-marker to))) | 859 (to (copy-marker to))) |
888 (widget-specify-text from to) | |
889 (set-marker-insertion-type from t) | 860 (set-marker-insertion-type from t) |
890 (set-marker-insertion-type to nil) | 861 (set-marker-insertion-type to nil) |
891 (widget-put widget :from from) | 862 (widget-put widget :from from) |
892 (widget-put widget :to to) | 863 (widget-put widget :to to) |
893 (when button-from | 864 (when button-from |
905 (defun widget-leave-text (widget) | 876 (defun widget-leave-text (widget) |
906 "Remove markers and overlays from WIDGET and its children." | 877 "Remove markers and overlays from WIDGET and its children." |
907 (let ((from (widget-get widget :from)) | 878 (let ((from (widget-get widget :from)) |
908 (to (widget-get widget :to)) | 879 (to (widget-get widget :to)) |
909 (button (widget-get widget :button-overlay)) | 880 (button (widget-get widget :button-overlay)) |
881 (sample (widget-get widget :sample-overlay)) | |
882 (doc (widget-get widget :doc-overlay)) | |
910 (field (widget-get widget :field-overlay)) | 883 (field (widget-get widget :field-overlay)) |
911 (children (widget-get widget :children))) | 884 (children (widget-get widget :children))) |
912 (set-marker from nil) | 885 (set-marker from nil) |
913 (set-marker to nil) | 886 (set-marker to nil) |
914 (when button | 887 (when button |
915 (delete-overlay button)) | 888 (delete-overlay button)) |
889 (when sample | |
890 (delete-overlay sample)) | |
891 (when doc | |
892 (delete-overlay doc)) | |
916 (when field | 893 (when field |
917 (delete-overlay field)) | 894 (delete-overlay field)) |
918 (mapcar 'widget-leave-text children))) | 895 (mapcar 'widget-leave-text children))) |
919 | 896 |
920 ;;; Keymap and Commands. | 897 ;;; Keymap and Commands. |
1104 widget | 1081 widget |
1105 nil) | 1082 nil) |
1106 widget)) | 1083 widget)) |
1107 nil))) | 1084 nil))) |
1108 | 1085 |
1086 (defcustom widget-use-overlay-change (string-match "XEmacs" emacs-version) | |
1087 "If non-nil, use overlay change functions to tab around in the buffer. | |
1088 This is much faster, but doesn't work reliably on Emacs 19.34." | |
1089 :type 'boolean | |
1090 :group 'widgets) | |
1091 | |
1109 (defun widget-move (arg) | 1092 (defun widget-move (arg) |
1110 "Move point to the ARG next field or button. | 1093 "Move point to the ARG next field or button. |
1111 ARG may be negative to move backward." | 1094 ARG may be negative to move backward." |
1112 (or (bobp) (> arg 0) (backward-char)) | 1095 (or (bobp) (> arg 0) (backward-char)) |
1113 (let ((pos (point)) | 1096 (let ((pos (point)) |
1114 (number arg) | 1097 (number arg) |
1115 (old (widget-tabable-at)) | 1098 (old (widget-tabable-at)) |
1116 new) | 1099 new) |
1117 ;; Forward. | 1100 ;; Forward. |
1118 (while (> arg 0) | 1101 (while (> arg 0) |
1119 (if (eobp) | 1102 (cond ((eobp) |
1120 (goto-char (point-min)) | 1103 (goto-char (point-min))) |
1121 (forward-char 1)) | 1104 (widget-use-overlay-change |
1105 (goto-char (next-overlay-change (point)))) | |
1106 (t | |
1107 (forward-char 1))) | |
1122 (and (eq pos (point)) | 1108 (and (eq pos (point)) |
1123 (eq arg number) | 1109 (eq arg number) |
1124 (error "No buttons or fields found")) | 1110 (error "No buttons or fields found")) |
1125 (let ((new (widget-tabable-at))) | 1111 (let ((new (widget-tabable-at))) |
1126 (when new | 1112 (when new |
1127 (unless (eq new old) | 1113 (unless (eq new old) |
1128 (setq arg (1- arg)) | 1114 (setq arg (1- arg)) |
1129 (setq old new))))) | 1115 (setq old new))))) |
1130 ;; Backward. | 1116 ;; Backward. |
1131 (while (< arg 0) | 1117 (while (< arg 0) |
1132 (if (bobp) | 1118 (cond ((bobp) |
1133 (goto-char (point-max)) | 1119 (goto-char (point-max))) |
1134 (backward-char 1)) | 1120 (widget-use-overlay-change |
1121 (goto-char (previous-overlay-change (point)))) | |
1122 (t | |
1123 (backward-char 1))) | |
1135 (and (eq pos (point)) | 1124 (and (eq pos (point)) |
1136 (eq arg number) | 1125 (eq arg number) |
1137 (error "No buttons or fields found")) | 1126 (error "No buttons or fields found")) |
1138 (let ((new (widget-tabable-at))) | 1127 (let ((new (widget-tabable-at))) |
1139 (when new | 1128 (when new |
1165 (interactive) | 1154 (interactive) |
1166 (let* ((field (widget-field-find (point))) | 1155 (let* ((field (widget-field-find (point))) |
1167 (start (and field (widget-field-start field)))) | 1156 (start (and field (widget-field-start field)))) |
1168 (if (and start (not (eq start (point)))) | 1157 (if (and start (not (eq start (point)))) |
1169 (goto-char start) | 1158 (goto-char start) |
1170 (call-interactively 'beginning-of-line)))) | 1159 (call-interactively 'beginning-of-line))) |
1160 ;; XEmacs: preserve the region | |
1161 (setq zmacs-region-stays t)) | |
1171 | 1162 |
1172 (defun widget-end-of-line () | 1163 (defun widget-end-of-line () |
1173 "Go to end of field or end of line, whichever is first." | 1164 "Go to end of field or end of line, whichever is first." |
1174 (interactive) | 1165 (interactive) |
1175 (let* ((field (widget-field-find (point))) | 1166 (let* ((field (widget-field-find (point))) |
1176 (end (and field (widget-field-end field)))) | 1167 (end (and field (widget-field-end field)))) |
1177 (if (and end (not (eq end (point)))) | 1168 (if (and end (not (eq end (point)))) |
1178 (goto-char end) | 1169 (goto-char end) |
1179 (call-interactively 'end-of-line)))) | 1170 (call-interactively 'end-of-line))) |
1171 ;; XEmacs: preserve the region | |
1172 (setq zmacs-region-stays t)) | |
1180 | 1173 |
1181 (defun widget-kill-line () | 1174 (defun widget-kill-line () |
1182 "Kill to end of field or end of line, whichever is first." | 1175 "Kill to end of field or end of line, whichever is first." |
1183 (interactive) | 1176 (interactive) |
1184 (let* ((field (widget-field-find (point))) | 1177 (let* ((field (widget-field-find (point))) |
1228 (widget-specify-field field | 1221 (widget-specify-field field |
1229 (marker-position from) (marker-position to)) | 1222 (marker-position from) (marker-position to)) |
1230 (set-marker from nil) | 1223 (set-marker from nil) |
1231 (set-marker to nil)))) | 1224 (set-marker to nil)))) |
1232 (widget-clear-undo) | 1225 (widget-clear-undo) |
1233 ;; We need to maintain text properties and size of the editing fields. | 1226 (widget-add-change)) |
1234 (make-local-variable 'after-change-functions) | |
1235 (setq after-change-functions | |
1236 (if widget-field-list '(widget-after-change) nil)) | |
1237 (when widget-field-use-before-change | |
1238 (make-local-variable 'before-change-functions) | |
1239 (setq before-change-functions | |
1240 (if widget-field-list '(widget-before-change) nil)))) | |
1241 | 1227 |
1242 (defvar widget-field-last nil) | 1228 (defvar widget-field-last nil) |
1243 ;; Last field containing point. | 1229 ;; Last field containing point. |
1244 (make-variable-buffer-local 'widget-field-last) | 1230 (make-variable-buffer-local 'widget-field-last) |
1245 | 1231 |
1259 | 1245 |
1260 (defun widget-field-end (widget) | 1246 (defun widget-field-end (widget) |
1261 "Return the end of WIDGET's editing field." | 1247 "Return the end of WIDGET's editing field." |
1262 (let ((overlay (widget-get widget :field-overlay))) | 1248 (let ((overlay (widget-get widget :field-overlay))) |
1263 ;; Don't subtract one if local-map works at the end of the overlay. | 1249 ;; Don't subtract one if local-map works at the end of the overlay. |
1264 (and overlay (if widget-field-add-space | 1250 (and overlay (if (or widget-field-add-space |
1251 (null (widget-get widget :size))) | |
1265 (1- (overlay-end overlay)) | 1252 (1- (overlay-end overlay)) |
1266 (overlay-end overlay))))) | 1253 (overlay-end overlay))))) |
1267 | 1254 |
1268 (defun widget-field-find (pos) | 1255 (defun widget-field-find (pos) |
1269 "Return the field at POS. | 1256 "Return the field at POS. |
1279 (when found | 1266 (when found |
1280 (debug "Overlapping fields")) | 1267 (debug "Overlapping fields")) |
1281 (setq found field)))) | 1268 (setq found field)))) |
1282 found)) | 1269 found)) |
1283 | 1270 |
1284 (defun widget-before-change (from &rest ignore) | 1271 (defun widget-before-change (from to) |
1285 ;; This is how, for example, a variable changes its state to `modified'. | 1272 ;; This is how, for example, a variable changes its state to `modified'. |
1286 ;; when it is being edited. | 1273 ;; when it is being edited. |
1287 (condition-case nil | 1274 (let ((from-field (widget-field-find from)) |
1288 (let ((field (widget-field-find from))) | 1275 (to-field (widget-field-find to))) |
1289 (widget-apply field :notify field)) | 1276 (cond ((not (eq from-field to-field)) |
1290 (error (debug "Before Change")))) | 1277 (add-hook 'post-command-hook 'widget-add-change nil t) |
1278 (error "Change should be restricted to a single field")) | |
1279 ((null from-field) | |
1280 (add-hook 'post-command-hook 'widget-add-change nil t) | |
1281 (error "Attempt to change text outside editable field")) | |
1282 (widget-field-use-before-change | |
1283 (condition-case nil | |
1284 (widget-apply from-field :notify from-field) | |
1285 (error (debug "Before Change"))))))) | |
1286 | |
1287 (defun widget-add-change () | |
1288 (make-local-hook 'post-command-hook) | |
1289 (remove-hook 'post-command-hook 'widget-add-change t) | |
1290 (make-local-hook 'before-change-functions) | |
1291 (add-hook 'before-change-functions 'widget-before-change nil t) | |
1292 (make-local-hook 'after-change-functions) | |
1293 (add-hook 'after-change-functions 'widget-after-change nil t)) | |
1291 | 1294 |
1292 (defun widget-after-change (from to old) | 1295 (defun widget-after-change (from to old) |
1293 ;; Adjust field size and text properties. | 1296 ;; Adjust field size and text properties. |
1294 (condition-case nil | 1297 (condition-case nil |
1295 (let ((field (widget-field-find from)) | 1298 (let ((field (widget-field-find from)) |
1481 (when value-pos | 1484 (when value-pos |
1482 (goto-char value-pos) | 1485 (goto-char value-pos) |
1483 (widget-apply widget :value-create))) | 1486 (widget-apply widget :value-create))) |
1484 (let ((from (copy-marker (point-min))) | 1487 (let ((from (copy-marker (point-min))) |
1485 (to (copy-marker (point-max)))) | 1488 (to (copy-marker (point-max)))) |
1486 (widget-specify-text from to) | |
1487 (set-marker-insertion-type from t) | 1489 (set-marker-insertion-type from t) |
1488 (set-marker-insertion-type to nil) | 1490 (set-marker-insertion-type to nil) |
1489 (widget-put widget :from from) | 1491 (widget-put widget :from from) |
1490 (widget-put widget :to to))) | 1492 (widget-put widget :to to))) |
1491 (widget-clear-undo)) | 1493 (widget-clear-undo)) |
1528 buttons)))) | 1530 buttons)))) |
1529 (t | 1531 (t |
1530 (error "Unknown escape `%c'" escape))) | 1532 (error "Unknown escape `%c'" escape))) |
1531 (widget-put widget :buttons buttons))) | 1533 (widget-put widget :buttons buttons))) |
1532 | 1534 |
1533 (defvar widget-button-face nil | |
1534 "Face to use for buttons. | |
1535 This is a variable so that it can be buffer-local.") | |
1536 | |
1537 (defun widget-default-button-face-get (widget) | 1535 (defun widget-default-button-face-get (widget) |
1538 ;; Use :button-face or widget-button-face | 1536 ;; Use :button-face or widget-button-face |
1539 (or (widget-get widget :button-face) | 1537 (or (widget-get widget :button-face) |
1540 (let ((parent (widget-get widget :parent))) | 1538 (let ((parent (widget-get widget :parent))) |
1541 (if parent | 1539 (if parent |
1542 (widget-apply parent :button-face-get) | 1540 (widget-apply parent :button-face-get) |
1543 'widget-button-face)))) | 1541 widget-button-face)))) |
1544 | 1542 |
1545 (defun widget-default-sample-face-get (widget) | 1543 (defun widget-default-sample-face-get (widget) |
1546 ;; Use :sample-face. | 1544 ;; Use :sample-face. |
1547 (widget-get widget :sample-face)) | 1545 (widget-get widget :sample-face)) |
1548 | 1546 |
1550 ;; Remove widget from the buffer. | 1548 ;; Remove widget from the buffer. |
1551 (let ((from (widget-get widget :from)) | 1549 (let ((from (widget-get widget :from)) |
1552 (to (widget-get widget :to)) | 1550 (to (widget-get widget :to)) |
1553 (inactive-overlay (widget-get widget :inactive)) | 1551 (inactive-overlay (widget-get widget :inactive)) |
1554 (button-overlay (widget-get widget :button-overlay)) | 1552 (button-overlay (widget-get widget :button-overlay)) |
1553 (sample-overlay (widget-get widget :sample-overlay)) | |
1554 (doc-overlay (widget-get widget :doc-overlay)) | |
1555 before-change-functions | 1555 before-change-functions |
1556 after-change-functions | 1556 after-change-functions |
1557 (inhibit-read-only t)) | 1557 (inhibit-read-only t)) |
1558 (widget-apply widget :value-delete) | 1558 (widget-apply widget :value-delete) |
1559 (when inactive-overlay | 1559 (when inactive-overlay |
1560 (delete-overlay inactive-overlay)) | 1560 (delete-overlay inactive-overlay)) |
1561 (when button-overlay | 1561 (when button-overlay |
1562 (delete-overlay button-overlay)) | 1562 (delete-overlay button-overlay)) |
1563 (when sample-overlay | |
1564 (delete-overlay sample-overlay)) | |
1565 (when doc-overlay | |
1566 (delete-overlay doc-overlay)) | |
1563 (when (< from to) | 1567 (when (< from to) |
1564 ;; Kludge: this doesn't need to be true for empty formats. | 1568 ;; Kludge: this doesn't need to be true for empty formats. |
1565 (delete-region from to)) | 1569 (delete-region from to)) |
1566 (set-marker from nil) | 1570 (set-marker from nil) |
1567 (set-marker to nil)) | 1571 (set-marker to nil)) |
1779 | 1783 |
1780 (defun widget-url-link-action (widget &optional event) | 1784 (defun widget-url-link-action (widget &optional event) |
1781 "Open the url specified by WIDGET." | 1785 "Open the url specified by WIDGET." |
1782 (require 'browse-url) | 1786 (require 'browse-url) |
1783 (funcall browse-url-browser-function (widget-value widget))) | 1787 (funcall browse-url-browser-function (widget-value widget))) |
1788 | |
1789 ;;; The `file-link' Widget. | |
1790 | |
1791 (define-widget 'file-link 'link | |
1792 "A link to a file." | |
1793 :action 'widget-file-link-action) | |
1794 | |
1795 (defun widget-file-link-action (widget &optional event) | |
1796 "Find the file specified by WIDGET." | |
1797 (find-file (widget-value widget))) | |
1798 | |
1799 ;;; The `emacs-library-link' Widget. | |
1800 | |
1801 (define-widget 'emacs-library-link 'link | |
1802 "A link to an Emacs Lisp library file." | |
1803 :action 'widget-emacs-library-link-action) | |
1804 | |
1805 (defun widget-emacs-library-link-action (widget &optional event) | |
1806 "Find the Emacs Library file specified by WIDGET." | |
1807 (find-file (locate-library (widget-value widget)))) | |
1808 | |
1809 ;;; The `emacs-commentary-link' Widget. | |
1810 | |
1811 (define-widget 'emacs-commentary-link 'link | |
1812 "A link to Commentary in an Emacs Lisp library file." | |
1813 :action 'widget-emacs-commentary-link-action) | |
1814 | |
1815 (defun widget-emacs-commentary-link-action (widget &optional event) | |
1816 "Find the Commentary section of the Emacs file specified by WIDGET." | |
1817 (finder-commentary (widget-value widget))) | |
1784 | 1818 |
1785 ;;; The `editable-field' Widget. | 1819 ;;; The `editable-field' Widget. |
1786 | 1820 |
1787 (define-widget 'editable-field 'default | 1821 (define-widget 'editable-field 'default |
1788 "An editable text field." | 1822 "An editable text field." |
2024 (widget-value-set widget | 2058 (widget-value-set widget |
2025 (widget-apply current :value-to-external | 2059 (widget-apply current :value-to-external |
2026 (widget-get current :value))) | 2060 (widget-get current :value))) |
2027 (widget-setup) | 2061 (widget-setup) |
2028 (widget-apply widget :notify widget event))) | 2062 (widget-apply widget :notify widget event))) |
2029 (run-hooks 'widget-edit-hook)) | 2063 (run-hook-with-args 'widget-edit-functions widget)) |
2030 | 2064 |
2031 (defun widget-choice-validate (widget) | 2065 (defun widget-choice-validate (widget) |
2032 ;; Valid if we have made a valid choice. | 2066 ;; Valid if we have made a valid choice. |
2033 (let ((void (widget-get widget :void)) | 2067 (let ((void (widget-get widget :void)) |
2034 (choice (widget-get widget :choice)) | 2068 (choice (widget-get widget :choice)) |
2080 | 2114 |
2081 (defun widget-toggle-action (widget &optional event) | 2115 (defun widget-toggle-action (widget &optional event) |
2082 ;; Toggle value. | 2116 ;; Toggle value. |
2083 (widget-value-set widget (not (widget-value widget))) | 2117 (widget-value-set widget (not (widget-value widget))) |
2084 (widget-apply widget :notify widget event) | 2118 (widget-apply widget :notify widget event) |
2085 (run-hooks 'widget-edit-hook)) | 2119 (run-hook-with-args 'widget-edit-functions widget)) |
2086 | 2120 |
2087 ;;; The `checkbox' Widget. | 2121 ;;; The `checkbox' Widget. |
2088 | 2122 |
2089 (define-widget 'checkbox 'toggle | 2123 (define-widget 'checkbox 'toggle |
2090 "A checkbox toggle." | 2124 "A checkbox toggle." |
2567 (let ((child (widget-editable-list-entry-create | 2601 (let ((child (widget-editable-list-entry-create |
2568 widget nil nil))) | 2602 widget nil nil))) |
2569 (when (< (widget-get child :entry-from) (widget-get widget :from)) | 2603 (when (< (widget-get child :entry-from) (widget-get widget :from)) |
2570 (set-marker (widget-get widget :from) | 2604 (set-marker (widget-get widget :from) |
2571 (widget-get child :entry-from))) | 2605 (widget-get child :entry-from))) |
2572 (widget-specify-text (widget-get child :entry-from) | |
2573 (widget-get child :entry-to)) | |
2574 (if (eq (car children) before) | 2606 (if (eq (car children) before) |
2575 (widget-put widget :children (cons child children)) | 2607 (widget-put widget :children (cons child children)) |
2576 (while (not (eq (car (cdr children)) before)) | 2608 (while (not (eq (car (cdr children)) before)) |
2577 (setq children (cdr children))) | 2609 (setq children (cdr children))) |
2578 (setcdr children (cons child (cdr children))))))) | 2610 (setcdr children (cons child (cdr children))))))) |
2642 :buttons (cons delete | 2674 :buttons (cons delete |
2643 (cons insert | 2675 (cons insert |
2644 (widget-get widget :buttons)))) | 2676 (widget-get widget :buttons)))) |
2645 (let ((entry-from (copy-marker (point-min))) | 2677 (let ((entry-from (copy-marker (point-min))) |
2646 (entry-to (copy-marker (point-max)))) | 2678 (entry-to (copy-marker (point-max)))) |
2647 (widget-specify-text entry-from entry-to) | |
2648 (set-marker-insertion-type entry-from t) | 2679 (set-marker-insertion-type entry-from t) |
2649 (set-marker-insertion-type entry-to nil) | 2680 (set-marker-insertion-type entry-to nil) |
2650 (widget-put child :entry-from entry-from) | 2681 (widget-put child :entry-from entry-from) |
2651 (widget-put child :entry-to entry-to))) | 2682 (widget-put child :entry-to entry-to))) |
2652 (widget-put insert :widget child) | 2683 (widget-put insert :widget child) |
2901 | 2932 |
2902 (define-widget 'regexp 'string | 2933 (define-widget 'regexp 'string |
2903 "A regular expression." | 2934 "A regular expression." |
2904 :match 'widget-regexp-match | 2935 :match 'widget-regexp-match |
2905 :validate 'widget-regexp-validate | 2936 :validate 'widget-regexp-validate |
2906 :value-face 'widget-single-line-field-face | 2937 ;; Doesn't work well with terminating newline. |
2938 ;; :value-face 'widget-single-line-field-face | |
2907 :tag "Regexp") | 2939 :tag "Regexp") |
2908 | 2940 |
2909 (defun widget-regexp-match (widget value) | 2941 (defun widget-regexp-match (widget value) |
2910 ;; Match valid regexps. | 2942 ;; Match valid regexps. |
2911 (and (stringp value) | 2943 (and (stringp value) |
2927 "A file widget. | 2959 "A file widget. |
2928 It will read a file name from the minibuffer when invoked." | 2960 It will read a file name from the minibuffer when invoked." |
2929 :complete-function 'widget-file-complete | 2961 :complete-function 'widget-file-complete |
2930 :prompt-value 'widget-file-prompt-value | 2962 :prompt-value 'widget-file-prompt-value |
2931 :format "%{%t%}: %v" | 2963 :format "%{%t%}: %v" |
2932 :value-face 'widget-single-line-field-face | 2964 ;; Doesn't work well with terminating newline. |
2965 ;; :value-face 'widget-single-line-field-face | |
2933 :tag "File") | 2966 :tag "File") |
2934 | 2967 |
2935 (defun widget-file-complete () | 2968 (defun widget-file-complete () |
2936 "Perform completion on file name preceding point." | 2969 "Perform completion on file name preceding point." |
2937 (interactive) | 2970 (interactive) |
3313 ;; Toggle a boolean. | 3346 ;; Toggle a boolean. |
3314 (y-or-n-p prompt)) | 3347 (y-or-n-p prompt)) |
3315 | 3348 |
3316 ;;; The `color' Widget. | 3349 ;;; The `color' Widget. |
3317 | 3350 |
3318 (define-widget 'color-item 'choice-item | 3351 (define-widget 'color 'editable-field |
3319 "A color name (with sample)." | 3352 "Choose a color name (with sample)." |
3320 :format "%v (%{sample%})\n" | 3353 :format "%t: %v (%{sample%})\n" |
3321 :sample-face-get 'widget-color-item-button-face-get) | 3354 :size 10 |
3322 | 3355 :tag "Color" |
3323 (defun widget-color-item-button-face-get (widget) | 3356 :value "black" |
3324 (let ((symbol (intern (concat "fg:" (widget-value widget))))) | 3357 :complete 'widget-color-complete |
3358 :sample-face-get 'widget-color-sample-face-get | |
3359 :notify 'widget-color-notify | |
3360 :action 'widget-color-action) | |
3361 | |
3362 (defun widget-color-complete (widget) | |
3363 "Complete the color in WIDGET." | |
3364 (let* ((prefix (buffer-substring-no-properties (widget-field-start widget) | |
3365 (point))) | |
3366 (list (widget-color-choice-list)) | |
3367 (completion (try-completion prefix list))) | |
3368 (cond ((eq completion t) | |
3369 (message "Exact match.")) | |
3370 ((null completion) | |
3371 (error "Can't find completion for \"%s\"" prefix)) | |
3372 ((not (string-equal prefix completion)) | |
3373 (insert-and-inherit (substring completion (length prefix)))) | |
3374 (t | |
3375 (message "Making completion list...") | |
3376 (let ((list (all-completions prefix list nil))) | |
3377 (with-output-to-temp-buffer "*Completions*" | |
3378 (display-completion-list list))) | |
3379 (message "Making completion list...done"))))) | |
3380 | |
3381 (defun widget-color-sample-face-get (widget) | |
3382 (let* ((value (condition-case nil | |
3383 (widget-value widget) | |
3384 (error (widget-get widget :value)))) | |
3385 (symbol (intern (concat "fg:" value)))) | |
3325 (if (string-match "XEmacs" emacs-version) | 3386 (if (string-match "XEmacs" emacs-version) |
3326 (prog1 symbol | 3387 (prog1 symbol |
3327 (or (find-face symbol) | 3388 (or (find-face symbol) |
3328 (set-face-foreground (make-face symbol) (widget-value widget)))) | 3389 (set-face-foreground (make-face symbol) value))) |
3329 (condition-case nil | 3390 (condition-case nil |
3330 (facemenu-get-face symbol) | 3391 (facemenu-get-face symbol) |
3331 (error 'default))))) | 3392 (error 'default))))) |
3332 | 3393 |
3333 (define-widget 'color 'push-button | |
3334 "Choose a color name (with sample)." | |
3335 :format "%[%t%]: %v" | |
3336 :tag "Color" | |
3337 :value "black" | |
3338 :value-create 'widget-color-value-create | |
3339 :value-delete 'widget-children-value-delete | |
3340 :value-get 'widget-color-value-get | |
3341 :value-set 'widget-color-value-set | |
3342 :action 'widget-color-action | |
3343 :match 'widget-field-match | |
3344 :tag "Color") | |
3345 | |
3346 (defvar widget-color-choice-list nil) | 3394 (defvar widget-color-choice-list nil) |
3347 ;; Variable holding the possible colors. | 3395 ;; Variable holding the possible colors. |
3348 | 3396 |
3349 (defun widget-color-choice-list () | 3397 (defun widget-color-choice-list () |
3350 (unless widget-color-choice-list | 3398 (unless widget-color-choice-list |
3351 (setq widget-color-choice-list | 3399 (setq widget-color-choice-list |
3352 (mapcar '(lambda (color) (list color)) | 3400 (if (fboundp 'read-color-completion-table) |
3353 (x-defined-colors)))) | 3401 (read-color-completion-table) |
3402 (mapcar '(lambda (color) (list color)) | |
3403 (x-defined-colors))))) | |
3354 widget-color-choice-list) | 3404 widget-color-choice-list) |
3355 | |
3356 (defun widget-color-value-create (widget) | |
3357 (let ((child (widget-create-child-and-convert | |
3358 widget 'color-item (widget-get widget :value)))) | |
3359 (widget-put widget :children (list child)))) | |
3360 | |
3361 (defun widget-color-value-get (widget) | |
3362 ;; Pass command to first child. | |
3363 (widget-apply (car (widget-get widget :children)) :value-get)) | |
3364 | |
3365 (defun widget-color-value-set (widget value) | |
3366 ;; Pass command to first child. | |
3367 (widget-apply (car (widget-get widget :children)) :value-set value)) | |
3368 | 3405 |
3369 (defvar widget-color-history nil | 3406 (defvar widget-color-history nil |
3370 "History of entered colors") | 3407 "History of entered colors") |
3371 | 3408 |
3372 (defun widget-color-action (widget &optional event) | 3409 (defun widget-color-action (widget &optional event) |
3373 ;; Prompt for a color. | 3410 ;; Prompt for a color. |
3374 (let* ((tag (widget-apply widget :menu-tag-get)) | 3411 (let* ((tag (widget-apply widget :menu-tag-get)) |
3375 (prompt (concat tag ": ")) | 3412 (prompt (concat tag ": ")) |
3376 (answer (cond ((string-match "XEmacs" emacs-version) | 3413 (value (widget-value widget)) |
3377 (read-color prompt)) | 3414 (start (widget-field-start widget)) |
3378 ((fboundp 'x-defined-colors) | 3415 (pos (cond ((< (point) start) |
3379 (completing-read (concat tag ": ") | 3416 0) |
3380 (widget-color-choice-list) | 3417 ((> (point) (+ start (length value))) |
3381 nil nil nil 'widget-color-history)) | 3418 (length value)) |
3382 (t | 3419 (t |
3383 (read-string prompt (widget-value widget)))))) | 3420 (- (point) start)))) |
3421 (answer (if (commandp 'read-color) | |
3422 (read-color prompt) | |
3423 (completing-read (concat tag ": ") | |
3424 (widget-color-choice-list) | |
3425 nil nil | |
3426 (cons value pos) | |
3427 'widget-color-history)))) | |
3384 (unless (zerop (length answer)) | 3428 (unless (zerop (length answer)) |
3385 (widget-value-set widget answer) | 3429 (widget-value-set widget answer) |
3386 (widget-setup) | 3430 (widget-setup) |
3387 (widget-apply widget :notify widget event)))) | 3431 (widget-apply widget :notify widget event)))) |
3432 | |
3433 (defun widget-color-notify (widget child &optional event) | |
3434 "Update the sample, and notofy the parent." | |
3435 (overlay-put (widget-get widget :sample-overlay) | |
3436 'face (widget-apply widget :sample-face-get)) | |
3437 (widget-default-notify widget child event)) | |
3388 | 3438 |
3389 ;;; The Help Echo | 3439 ;;; The Help Echo |
3390 | 3440 |
3391 (defun widget-echo-help-mouse () | 3441 (defun widget-echo-help-mouse () |
3392 "Display the help message for the widget under the mouse. | 3442 "Display the help message for the widget under the mouse. |