Mercurial > hg > xemacs-beta
comparison lisp/utils/annotations.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 0293115a14e9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; annotations.el --- interface to marginal annotations | |
2 | |
3 ;; Copyright (C) 1992-1994 Free Software Foundation, Inc. | |
4 ;; | |
5 ;; Created: 10-Oct-93, Chuck Thompson <cthomp@cs.uiuc.edu> | |
6 ;; Keywords: extensions, hypermedia, outlining | |
7 ;; Enhanced by Andy Piper <ajp@eng.cam.ac.uk>: 6-may-94 | |
8 ;; | |
9 ;; Last modified: 12-May-95 by Chuck Thompson. | |
10 | |
11 ;; This file is part of XEmacs. | |
12 | |
13 ;; XEmacs is free software; you can redistribute it and/or modify it | |
14 ;; under the terms of the GNU General Public License as published by | |
15 ;; the Free Software Foundation; either version 2, or (at your option) | |
16 ;; any later version. | |
17 | |
18 ;; XEmacs is distributed in the hope that it will be useful, but | |
19 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
21 ;; General Public License for more details. | |
22 | |
23 ;; You should have received a copy of the GNU General Public License | |
24 ;; along with XEmacs; see the file COPYING. If not, write to the Free | |
25 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
26 | |
27 ;;; Synched up with: Not in FSF. | |
28 | |
29 ;; | |
30 ;; The annotations are implemented on top of extents. The extent property | |
31 ;; 'annotation of an extent being used as an annotation is vector of size 6: | |
32 ;; [<data> <action> <menu> <glyph> <down-glyph> <rightp>] | |
33 ;; | |
34 | |
35 ;;;###autoload | |
36 (defvar make-annotation-hook nil | |
37 "*Function or functions to run immediately after creating an annotation.") | |
38 | |
39 ;;;###autoload | |
40 (defvar before-delete-annotation-hook nil | |
41 "*Function or functions to run immediately before deleting an annotation.") | |
42 | |
43 ;;;###autoload | |
44 (defvar after-delete-annotation-hook nil | |
45 "*Function or functions to run immediately after deleting an annotation.") | |
46 | |
47 (defvar annotation-local-map-default | |
48 (let ((map (make-sparse-keymap))) | |
49 (set-keymap-name map 'annotation-local-map) | |
50 (define-key map 'button1 'annotation-activate-function-default) | |
51 (define-key map 'button3 'annotation-popup-menu) | |
52 map) | |
53 "Keymap used to activate annotations with only annotation data passed.") | |
54 | |
55 (defvar annotation-local-map-with-event | |
56 (let ((map (make-sparse-keymap))) | |
57 (set-keymap-name map 'annotation-local-map) | |
58 (define-key map 'button1 'annotation-activate-function-with-event) | |
59 (define-key map 'button3 'annotation-popup-menu) | |
60 map) | |
61 "Keymap used to activate annotations with annotation data and event passed.") | |
62 | |
63 ;; | |
64 ;; When the mouse is pressed and released over an annotation glyph | |
65 ;; this will run the annotation action passing a single arg, the value | |
66 ;; of the annotation data field. | |
67 ;; | |
68 (defun annotation-activate-function-default (event) | |
69 (interactive "e") | |
70 (let ((extent (event-glyph-extent event)) | |
71 (mouse-down t) | |
72 (up-glyph nil)) | |
73 ;; make the glyph look pressed | |
74 (cond ((annotation-down-glyph extent) | |
75 (setq up-glyph (annotation-glyph extent)) | |
76 (set-annotation-glyph extent (annotation-down-glyph extent)))) | |
77 (while mouse-down | |
78 (setq event (next-event event)) | |
79 (if (button-release-event-p event) | |
80 (setq mouse-down nil))) | |
81 ;; make the glyph look released | |
82 (cond ((annotation-down-glyph extent) | |
83 (set-annotation-glyph extent up-glyph))) | |
84 (if (eq extent (event-glyph-extent event)) | |
85 (if (annotation-action extent) | |
86 (funcall (annotation-action extent) (annotation-data extent)))))) | |
87 | |
88 ;; | |
89 ;; When the mouse is pressed and released over an annotation glyph | |
90 ;; this will run the annotation action passing two args, the value | |
91 ;; of the annotation data field and the event which triggered the | |
92 ;; annotation. | |
93 ;; | |
94 (defun annotation-activate-function-with-event (event) | |
95 (interactive "e") | |
96 (let ((extent (event-glyph-extent event)) | |
97 (mouse-down t) | |
98 (up-glyph nil)) | |
99 ;; make the glyph look pressed | |
100 (cond ((annotation-down-glyph extent) | |
101 (setq up-glyph (annotation-glyph extent)) | |
102 (set-annotation-glyph extent (annotation-down-glyph extent)))) | |
103 (while mouse-down | |
104 (setq event (next-event event)) | |
105 (if (button-release-event-p event) | |
106 (setq mouse-down nil))) | |
107 ;; make the glyph look released | |
108 (cond ((annotation-down-glyph extent) | |
109 (set-annotation-glyph extent up-glyph))) | |
110 (if (eq extent (event-glyph-extent event)) | |
111 (if (annotation-action extent) | |
112 (funcall (annotation-action extent) (annotation-data extent) | |
113 event))))) | |
114 | |
115 ;; #### Glyphs should be glyphs should be glyphs | |
116 ;;;###autoload | |
117 (defun make-annotation (glyph &optional pos layout buffer with-event d-glyph rightp) | |
118 "Create a marginal annotation, displayed using GLYPH, at position POS. | |
119 GLYPH may be either a glyph object or a string. Use layout policy | |
120 LAYOUT and place the annotation in buffer BUFFER. If POS is nil, point is | |
121 used. If LAYOUT is nil, `whitespace' is used. If BUFFER is nil, the | |
122 current buffer is used. If WITH-EVENT is non-nil, then when an annotation | |
123 is activated, the triggering event is passed as the second arg to the | |
124 annotation function. If D-GLYPH is non-nil then it is used as the glyph | |
125 that will be displayed when button1 is down. If RIGHTP is non-nil then | |
126 the glyph will be displayed on the right side of the buffer instead of the | |
127 left." | |
128 (let ((new-annotation)) | |
129 ;; get the buffer to add the annotation at | |
130 (if (not buffer) | |
131 (setq buffer (current-buffer)) | |
132 (setq buffer (get-buffer buffer))) | |
133 ;; get the position to put it at | |
134 (if (not pos) | |
135 (save-excursion | |
136 (set-buffer buffer) | |
137 (setq pos (point)))) | |
138 ;; make sure it gets some layout policy | |
139 (if (not layout) | |
140 (setq layout 'whitespace)) | |
141 | |
142 ;; make sure the glyph arguments are actually glyphs | |
143 (if (and glyph (not (glyphp glyph))) | |
144 (setq glyph (make-glyph glyph))) | |
145 (if (and d-glyph (not (glyphp d-glyph))) | |
146 (setq d-glyph (make-glyph d-glyph))) | |
147 | |
148 ;; create the actual annotation | |
149 (setq new-annotation (make-extent pos pos buffer)) | |
150 (detach-extent new-annotation) | |
151 (set-extent-endpoints new-annotation pos pos) | |
152 (if rightp | |
153 (set-extent-end-glyph new-annotation glyph layout) | |
154 (set-extent-begin-glyph new-annotation glyph layout)) | |
155 (set-extent-property new-annotation 'annotation | |
156 (vector nil nil nil glyph d-glyph rightp)) | |
157 (set-extent-property new-annotation 'end-closed t) | |
158 (set-extent-property new-annotation 'start-open t) | |
159 (set-extent-property new-annotation 'duplicable t) | |
160 (if with-event | |
161 (set-extent-property new-annotation 'keymap | |
162 annotation-local-map-with-event) | |
163 (set-extent-property new-annotation 'keymap | |
164 annotation-local-map-default)) | |
165 (run-hook-with-args 'make-annotation-hook new-annotation) | |
166 new-annotation)) | |
167 | |
168 (fset 'make-graphic-annotation 'make-annotation) | |
169 (make-obsolete 'make-graphic-annotation 'make-annotation) | |
170 | |
171 ;;;###autoload | |
172 (defun delete-annotation (annotation) | |
173 "Remove ANNOTATION from its buffer. This does not modify the buffer text." | |
174 (if (not (annotationp annotation)) | |
175 (error "%s is not an annotation" annotation) | |
176 (progn | |
177 (run-hook-with-args 'before-delete-annotation-hook annotation) | |
178 (delete-extent annotation) | |
179 (run-hooks 'after-delete-annotation-hook)))) | |
180 | |
181 ;;;###autoload | |
182 (defun annotationp (annotation) | |
183 "T if OBJECT is an annotation." | |
184 (and (extent-live-p annotation) | |
185 (not (null (extent-property annotation 'annotation))))) | |
186 | |
187 (defun annotation-visible (annotation) | |
188 "T if there is enough available space to display ANNOTATION." | |
189 (if (not (annotationp annotation)) | |
190 (error "%s is not an annotation" annotation) | |
191 (not (extent-property annotation 'glyph-invisible)))) | |
192 | |
193 ;;;###autoload | |
194 (defun annotation-at (&optional pos buffer) | |
195 "Return the first annotation at POS in BUFFER. | |
196 BUFFER defaults to the current buffer. POS defaults to point in BUFFER." | |
197 (car (annotations-at pos buffer))) | |
198 (make-obsolete 'annotation-at 'annotations-at) | |
199 | |
200 (defun annotation-layout (annotation) | |
201 "Return the layout policy of annotation ANNOTATION. The layout policy | |
202 is set using `set-annotation-layout'." | |
203 (if (not (annotationp annotation)) | |
204 (error "%s is not an annotation" annotation) | |
205 (if (eq 'right (annotation-side annotation)) | |
206 (extent-end-glyph-layout annotation) | |
207 (extent-begin-glyph-layout annotation)))) | |
208 | |
209 | |
210 (defun annotation-side (annotation) | |
211 "Return the side of the buffer the annotation is displayed on. | |
212 Return value is either 'left or 'right." | |
213 (if (aref (extent-property annotation 'annotation) 5) | |
214 'right | |
215 'left)) | |
216 | |
217 (defun set-annotation-layout (annotation layout) | |
218 "Set the layout policy of ANNOTATION to LAYOUT. The function | |
219 `annotation-layout' returns the current layout policy." | |
220 (if (not (annotationp annotation)) | |
221 (error "%s is not an annotation" annotation) | |
222 (if (eq 'right (annotation-side annotation)) | |
223 (set-extent-end-glyph-layout annotation layout) | |
224 (set-extent-begin-glyph-layout annotation layout)))) | |
225 | |
226 ;; Now that annotatios use glyphs this function has little value and | |
227 ;; will actually not work as is. | |
228 ;(defun annotation-type (annotation) | |
229 ; "Return the display type of the annotation ANNOTATION. The type will | |
230 ;be one of the following symbols: | |
231 ; | |
232 ; pixmap | |
233 ; bitmap | |
234 ; string | |
235 ; nil (the object is not an annotation)" | |
236 ; (if (not (annotationp annotation)) | |
237 ; nil | |
238 ; (let ((glyph (annotation-glyph annotation))) | |
239 ; (if (stringp glyph) | |
240 ; 'stringp | |
241 ; (if (not (pixmapp glyph)) | |
242 ; (error "%s is a corrupt annotation" annotation) | |
243 ; (if (> (pixmap-depth glyph) 0) | |
244 ; 'pixmap | |
245 ; 'bitmap)))))) | |
246 (make-obsolete 'annotation-type "This function no longer has any meaning.") | |
247 | |
248 (defun annotation-width (annotation) | |
249 "Return the width of the annotation ANNOTATION in pixels." | |
250 (if (not (annotationp annotation)) | |
251 (error "%s is not an annotation" annotation) | |
252 (glyph-width (annotation-glyph annotation)))) | |
253 | |
254 (defun annotation-glyph (annotation) | |
255 "If ANNOTATION is of type `string' return the string. Otherwise, return | |
256 the glyph object used to display ANNOTATION. The glyph is set using | |
257 `set-annotation-glyph'." | |
258 (if (not (annotationp annotation)) | |
259 (error "%s is not an annotation" annotation) | |
260 (aref (extent-property annotation 'annotation) 3))) | |
261 | |
262 (defun set-annotation-glyph (annotation glyph &optional layout side) | |
263 "Set the representation of ANNOTATION to GLYPH. | |
264 GLYPH should be a glyph object. If LAYOUT is non-nil, set the layout | |
265 policy of the annotation to LAYOUT. If SIDE is equal to 'left or 'right | |
266 change the side of the annotation to that value. | |
267 The function `annotation-glyph' returns the current glyph." | |
268 (if (not (annotationp annotation)) | |
269 (error "%s is not an annotation" annotation) | |
270 (progn | |
271 (if (not layout) | |
272 (setq layout (extent-layout annotation))) | |
273 (if (or (eq side 'right) | |
274 (and (not (eq side 'left)) | |
275 (eq (annotation-side annotation) 'right))) | |
276 (set-extent-end-glyph annotation glyph layout) | |
277 (set-extent-begin-glyph annotation glyph layout)) | |
278 (aset (extent-property annotation 'annotation) 3 glyph) | |
279 (if (eq side 'right) | |
280 (aset (extent-property annotation 'annotation) 5 t)) | |
281 (if (eq side 'left) | |
282 (aset (extent-property annotation 'annotation) 5 nil)) | |
283 (annotation-glyph annotation)))) | |
284 | |
285 (defun annotation-down-glyph (annotation) | |
286 "If ANNOTATION is of type `string' return the down string. Otherwise, | |
287 return the glyph object of the down-glyph representing ANNOTATION. | |
288 The down-glyph is set using `set-annotation-down-glyph'." | |
289 (if (not (annotationp annotation)) | |
290 (error "%s is not an annotation" annotation) | |
291 (aref (extent-property annotation 'annotation) 4))) | |
292 | |
293 (defun set-annotation-down-glyph (annotation glyph) | |
294 "Set the depressed representation of ANNOTATION to GLYPH. | |
295 GLYPH should be a glyph object. | |
296 The function `annotation-down-glyph' returns the current down-glyph." | |
297 (if (not (annotationp annotation)) | |
298 (error "%s is not an annotation" annotation) | |
299 (aset (extent-property annotation 'annotation) 4 glyph))) | |
300 | |
301 (define-obsolete-function-alias 'annotation-graphic 'annotation-glyph) | |
302 (define-obsolete-function-alias 'set-annotation-graphic 'set-annotation-glyph) | |
303 | |
304 (defun annotation-data (annotation) | |
305 "Return the data associated with annotation ANNOTATION. The data is | |
306 set using `set-annotation-data'." | |
307 (if (not (annotationp annotation)) | |
308 (error "%s is not an annotation" annotation) | |
309 (aref (extent-property annotation 'annotation) 0))) | |
310 | |
311 (defun set-annotation-data (annotation data) | |
312 "Set the data field of ANNOTATION to DATA. | |
313 The function `annotation-data' returns the current data." | |
314 (if (not (annotationp annotation)) | |
315 (error "%s is not an annotation" annotation) | |
316 (aset (extent-property annotation 'annotation) 0 data))) | |
317 | |
318 (defun annotation-action (annotation) | |
319 "Return the action associated with annotation ANNOTATION. The action | |
320 is set using `set-annotation-action'." | |
321 (if (not (annotationp annotation)) | |
322 (error "%s is not an annotation" annotation) | |
323 (aref (extent-property annotation 'annotation) 1))) | |
324 | |
325 (defun set-annotation-action (annotation action) | |
326 "Set the action field of ANNOTATION to ACTION. | |
327 The function `annotation-action' returns the current action." | |
328 (if (not (annotationp annotation)) | |
329 (error "%s is not an annotation" annotation) | |
330 (aset (extent-property annotation 'annotation) 1 action))) | |
331 | |
332 (defun annotation-face (annotation) | |
333 "Return the face associated with annotation ANNOTATION. | |
334 The face is set using `set-annotation-face'." | |
335 (if (not (annotationp annotation)) | |
336 (error "%s is not an annotation" annotation) | |
337 (extent-face annotation))) | |
338 | |
339 (defun set-annotation-face (annotation face) | |
340 "Set the face associated with annotation ANNOTATION to FACE. | |
341 The function `annotation-face' returns the current face." | |
342 (if (not (annotationp annotation)) | |
343 (error "%s is not an annotation" annotation) | |
344 (set-extent-face annotation face))) | |
345 | |
346 (defun hide-annotation (annotation) | |
347 "Remove ANNOTATION's glyph so that it is invisible." | |
348 (if (eq (annotation-side annotation) 'left) | |
349 (set-extent-begin-glyph annotation nil) | |
350 (set-extent-end-glyph annotation nil))) | |
351 (define-obsolete-function-alias 'annotation-hide 'hide-annotation) | |
352 | |
353 (defun reveal-annotation (annotation) | |
354 "Add ANNOTATION's glyph so that it is visible." | |
355 (if (eq (annotation-side annotation) 'left) | |
356 (set-extent-begin-glyph annotation (annotation-glyph annotation)) | |
357 (set-extent-end-glyph annotation (annotation-glyph annotation)))) | |
358 (define-obsolete-function-alias 'annotation-reveal 'reveal-annotation) | |
359 | |
360 ;;;###autoload | |
361 (defun annotations-in-region (start end buffer) | |
362 "Return all annotations in BUFFER between START and END inclusively." | |
363 (save-excursion | |
364 (set-buffer buffer) | |
365 | |
366 (if (< start (point-min)) | |
367 (error "<start> not in range of buffer")) | |
368 (if (> end (point-max)) | |
369 (error "<end> not in range of buffer")) | |
370 | |
371 (let (note-list) | |
372 (map-extents | |
373 (function (lambda (extent dummy) | |
374 (progn | |
375 (if (annotationp extent) | |
376 (setq note-list (cons extent note-list))) | |
377 nil))) | |
378 buffer start end nil t) | |
379 note-list))) | |
380 | |
381 ;;;###autoload | |
382 (defun annotations-at (&optional pos buffer) | |
383 "Return a list of all annotations at POS in BUFFER. | |
384 If BUFFER is nil, the current buffer is used. If POS is nil, point is used." | |
385 (if (not buffer) | |
386 (setq buffer (current-buffer))) | |
387 (if (not pos) | |
388 (save-excursion | |
389 (set-buffer buffer) | |
390 (setq pos (point)))) | |
391 | |
392 (annotations-in-region pos pos buffer) | |
393 ) | |
394 | |
395 ;;;###autoload | |
396 (defun annotation-list (&optional buffer) | |
397 "Return a list of all annotations in BUFFER. | |
398 If BUFFER is nil, the current buffer is used." | |
399 (if (not buffer) | |
400 (setq buffer (current-buffer))) | |
401 | |
402 (save-excursion | |
403 (set-buffer buffer) | |
404 (annotations-in-region (point-min) (point-max) buffer))) | |
405 | |
406 ;;;###autoload | |
407 (defun all-annotations () | |
408 "Return a list of all annotations in existence." | |
409 (let ((b (buffer-list)) | |
410 result) | |
411 (while b | |
412 (setq result (nconc result (annotation-list (car b)))) | |
413 (setq b (cdr b))) | |
414 result)) | |
415 | |
416 ;;; #### really this menus junk should append to the prevailing menu | |
417 ;;; in the same way `popup-mode-menu' does. --jwz | |
418 | |
419 ;; annotations menu stuff | |
420 (defun annotation-popup-menu (event) | |
421 "Pop up a menu of annotations commands. | |
422 Point is temporarily moved to the click position." | |
423 (interactive "e") | |
424 (let ((extent (event-glyph-extent event))) | |
425 (save-excursion | |
426 (goto-char (extent-end-position extent)) | |
427 (if (annotation-menu extent) | |
428 (popup-menu (annotation-menu extent)) | |
429 (popup-mode-menu))))) | |
430 | |
431 (defun set-annotation-menu (annotation menu) | |
432 "Set the menu field of ANNOTATION to MENU. The function | |
433 `annotation-menu' returns the current menu." | |
434 (if (not (annotationp annotation)) | |
435 (error "%s is not an annotation" annotation) | |
436 (aset (extent-property annotation 'annotation) 2 menu))) | |
437 | |
438 (defun annotation-menu (annotation) | |
439 "Return the menu associated with annotation ANNOTATION. The menu | |
440 is set using `set-annotation-menu'." | |
441 (if (not (annotationp annotation)) | |
442 (error "%s is not an annotation" annotation) | |
443 (aref (extent-property annotation 'annotation) 2))) | |
444 | |
445 (provide 'annotations) |