comparison lisp/modes/xpm-mode.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; xpm-mode.el --- minor mode for editing XPM files
2
3 ;; Copyright (C) 1995 Joe Rumsey <ogre@netcom.com>
4 ;; Copyright (C) 1995 Rich Williams <rdw@hplb.hpl.hp.com>
5
6 ;; Authors: Joe Rumsey <ogre@netcom.com>
7 ;; Rich Williams <rdw@hplb.hpl.hp.com>
8 ;; Cleanup: Chuck Thompson <cthomp@cs.uiuc.edu>
9
10 ;; Version: 1.5
11 ;; Last Modified: Rich Williams <rdw@hplb.hpl.hp.com>, 13 July 1995
12 ;; Keywords: data tools
13
14 ;; This file is part of XEmacs.
15
16 ;; XEmacs is free software; you can redistribute it and/or modify it
17 ;; under the terms of the GNU General Public License as published by
18 ;; the Free Software Foundation; either version 2, or (at your option)
19 ;; any later version.
20
21 ;; XEmacs is distributed in the hope that it will be useful, but
22 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 ;; General Public License for more details.
25
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with XEmacs; see the file COPYING. If not, write to the Free
28 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
29
30 ;;; Synched up with: Not in FSF.
31
32 ;;
33 ;; xpm mode: Display xpm files in color
34 ;;
35 ;; thanks to Rich Williams for mods to do this without font-lock-mode,
36 ;; resulting in much improved performance and a better display
37 ;; (headers don't get colored strangely). Also for the palette toolbar.
38 ;;
39 ;; Non-standard minor mode in that it starts picture-mode automatically.
40 ;;
41 ;; To get this turned on automatically for .xpms, add an entry
42 ;; ("\\.xpm" . xpm-mode)
43 ;; to your auto-mode-alist. For example, my .emacs has this: (abbreviated)
44 ;; (setq auto-mode-alist (mapcar 'purecopy
45 ;; '(("\\.c$" . c-mode)
46 ;; ("\\.h$" . c-mode)
47 ;; ("\\.el$" . emacs-lisp-mode)
48 ;; ("\\.emacs$" . emacs-lisp-mode)
49 ;; ("\\.a$" . c-mode)
50 ;; ("\\.xpm" . xpm-mode))))
51 ;; (autoload 'xpm-mode "xpm-mode")
52 ;;
53 ;; I am a lisp newbie, practically everything in here I had to look up
54 ;; in the manual. It probably shows, suggestions for coding
55 ;; improvements are welcomed.
56 ;;
57 ;; May fail on some xpm's. Seems to be fine with files generated by
58 ;; xpaint and ppmtoxpm anyway. Will definitely fail on xpm's with
59 ;; more than one character per pixel. Not that hard to fix, but I've
60 ;; never seen one like that.
61 ;;
62 ;; If your default font is proportional, this will not be very useful.
63 ;;
64
65 (require 'annotations)
66
67 (defvar xpm-pixel-values nil)
68 (defvar xpm-glyph nil)
69 (defvar xpm-anno nil)
70 (defvar xpm-paint-string nil)
71 (defvar xpm-chars-per-pixel 1)
72 (defvar xpm-palette nil)
73 (defvar xpm-always-update-image nil
74 "If non-nil, update actual-size image after every click or drag movement.
75 Otherwise, only update on button releases or when asked to. This is slow.")
76
77 (make-variable-buffer-local 'xpm-palette)
78 (make-variable-buffer-local 'xpm-chars-per-pixel)
79 (make-variable-buffer-local 'xpm-paint-string)
80 (make-variable-buffer-local 'xpm-glyph)
81 (make-variable-buffer-local 'xpm-anno)
82 (make-variable-buffer-local 'xpm-pixel-values)
83 ;(make-variable-buffer-local 'xpm-faces-used)
84
85 (defun xpm-make-face (name)
86 "Makes a face with name xpm-NAME, and colour NAME."
87 (let ((face (make-face (intern (concat "xpm-" name))
88 "Temporary xpm-mode face" t)))
89 (set-face-background face name)
90 (set-face-foreground face "black")
91 face))
92
93 (defun xpm-init ()
94 "Treat the current buffer as an xpm file and colorize it."
95 (interactive)
96 (require 'picture)
97
98 (setq xpm-pixel-values nil)
99 (xpm-clear-extents)
100 (setq xpm-palette nil)
101
102 (message "Finding number of colors...")
103 (save-excursion
104 (goto-char (point-min))
105 (beginning-of-line)
106 (next-line 1)
107 (while (not (looking-at "\\s-*\""))
108 (next-line 1))
109 (next-line 1)
110 (while (not (looking-at "\\s-*\""))
111 (next-line 1))
112 (let ((co 0))
113 (while (< co (xpm-num-colors))
114 (progn
115 (xpm-parse-color)
116 (setq co (1+ co))
117 (next-line 1)
118 (beginning-of-line)))))
119 (if (not (eq major-mode 'picture-mode))
120 (picture-mode))
121 (set-specifier left-toolbar-width (cons (selected-frame) 16))
122 (set-specifier left-toolbar (cons (current-buffer) xpm-palette))
123 (message "Parsing body...")
124 (xpm-color-data)
125 (message "Parsing body...done")
126 (xpm-show-image))
127
128 (defun xpm-clear-extents ()
129 (let (cur-extent
130 next-extent)
131 (setq cur-extent (next-extent (current-buffer)))
132 (setq next-extent (next-extent cur-extent))
133 (while cur-extent
134 (delete-extent cur-extent)
135 (setq cur-extent next-extent)
136 (setq next-extent (next-extent cur-extent)))))
137
138 (defun xpm-color-data ()
139 (interactive)
140 (save-excursion
141 (xpm-goto-body-line 0)
142 (let (ext
143 pixel-chars
144 pixel-color)
145 (while (< (point) (point-max))
146 (setq pixel-chars
147 (buffer-substring (point) (+ (point) xpm-chars-per-pixel))
148 pixel-color (assoc pixel-chars xpm-pixel-values)
149 ext (make-extent (point) (+ (point) xpm-chars-per-pixel)))
150 (if pixel-color
151 (progn
152 (set-extent-face ext (cdr pixel-color)))
153 (set-extent-face ext 'default))
154 (forward-char xpm-chars-per-pixel)))))
155
156 (defun xpm-num-colors ()
157 (save-excursion
158 (goto-char (point-min))
159 (if (re-search-forward
160 "\"\\s-*\\([0-9]+\\)\\s-+\\([0-9]+\\)\\s-+\\([0-9]+\\)\\s-+\\([0-9]+\\)\\s-*"
161 (point-max) t)
162 (string-to-int (match-string 3))
163 (error "Unable to parse xpm information"))))
164
165 (defun xpm-make-solid-pixmap (colour width height)
166 (let ((x 0)
167 (y 0)
168 (line nil)
169 (total nil))
170 (setq line ",\n\"")
171 (while (< x width)
172 (setq line (concat line ".")
173 x (+ x 1)))
174 (setq line (concat line "\"")
175 total (format "/* XPM */\nstatic char * %s[] = {\n\"%d %d 1 1\",\n\". c %s\""
176 colour width height colour))
177 (while (< y height)
178 (setq total (concat total line)
179 y (+ y 1)))
180 (make-glyph (concat total "};\n"))))
181
182 (defun xpm-store-color (str color)
183 "Add STR to xpm-pixel-values with a new face set to background COLOR
184 if STR already has an entry, the existing face will be used, with the
185 new color replacing the old (on the display only, not in the xpm color
186 defs!)"
187 (let (new-face)
188 (setq new-face (xpm-make-face color))
189 (set-face-background new-face color)
190 (let ((ccc (color-rgb-components (make-color-specifier color))))
191 (if (> (length ccc) 0)
192 (if (or (or (> (elt ccc 0) 32767)
193 (> (elt ccc 1) 32767))
194 (> (elt ccc 2) 32767))
195 (set-face-foreground new-face "black")
196 (set-face-foreground new-face "white"))))
197 (setq xpm-pixel-values (cons (cons str new-face) xpm-pixel-values)
198 xpm-palette
199 (cons (vector
200 (list (xpm-make-solid-pixmap color 12 12))
201 ;; Major cool things with quotes.....
202 (`
203 (lambda (event)
204 (interactive "e")
205 (xpm-toolbar-select-colour event (, str))))
206 t
207 color) xpm-palette))
208 ))
209
210 (defun xpm-parse-color ()
211 "Parse xpm color string from current line and set the color"
212 (interactive)
213 (let (end)
214 (save-excursion
215 (end-of-line)
216 (setq end (point))
217 (beginning-of-line)
218 (if (re-search-forward
219 ;; Generate a regexp on the fly
220 (concat "\"\\(" (make-string xpm-chars-per-pixel ?.) "\\)" ; chars
221 "\\s-+\\([c]\\)" ; there are more classes than 'c'
222 "\\s-+\\([^\"]+\\)\"")
223 end t)
224 (progn
225 (xpm-store-color (match-string 1) (match-string 3))
226 (list (match-string 1) (match-string 3)))
227 (error "Unable to parse color")))))
228
229 (defun xpm-add-color (str color)
230 "add a color to an xpm's list of color defs"
231 (interactive "sPixel character:
232 sPixel color (any valid X color string):")
233 (save-excursion
234 (goto-char (point-min))
235 (while (not (looking-at "\\s-*\""))
236 (next-line 1))
237 (next-line 1)
238 (while (not (looking-at "\\s-*\""))
239 (next-line 1))
240 (let ((co 0))
241 (while (< co (xpm-num-colors))
242 (next-line 1)
243 (setq co (1+ co))))
244 (insert (format "\"%s\tc %s\",\n" str color))
245 (previous-line 1)
246 (xpm-parse-color)
247
248 (goto-char (point-min))
249 (while (not (looking-at "\\s-*\""))
250 (next-line 1))
251 (let ((entry 0))
252 (while (or (= (char-after (point)) ? ) (= (char-after (point)) ?\"))
253 (forward-char 1))
254 (while (< entry 2)
255 (progn
256 (if (eq (char-after (point)) ? )
257 (progn
258 (setq entry (1+ entry))
259 (while (eq (char-after (point)) ? )
260 (forward-char 1)))
261 (forward-char 1))))
262 (let ((old-colors (xpm-num-colors)))
263 (while (and (>= (char-after (point)) ?0) (<= (char-after (point)) ?9))
264 (delete-char 1))
265 (insert (int-to-string (1+ old-colors)))))))
266
267
268 (defun xpm-goto-color-def (def)
269 "move to color DEF in the xpm header"
270 (interactive "nColor number:")
271 (goto-char (point-min))
272 (while (not (looking-at "\\s-*\""))
273 (next-line 1))
274 (next-line 1)
275 (while (not (looking-at "\\s-*\""))
276 (next-line 1))
277 (next-line def))
278
279 (defun xpm-goto-body-line (line)
280 "move to LINE lines down from the start of the body of an xpm"
281 (interactive "nBody line:")
282 (goto-char (point-min))
283 (xpm-goto-color-def (xpm-num-colors))
284 (next-line line))
285
286 (defun xpm-show-image ()
287 "Display the xpm in the current buffer at the end of the topmost line"
288 (interactive)
289 (save-excursion
290 (if (annotationp xpm-anno)
291 (delete-annotation xpm-anno))
292 (setq xpm-glyph (make-glyph
293 (vector 'xpm :data
294 (buffer-substring (point-min) (point-max)))))
295 (goto-char (point-min))
296 (end-of-line)
297 (setq xpm-anno (make-annotation xpm-glyph (point) 'text))))
298
299 (defun xpm-hide-image ()
300 "Remove the image of the xpm from the buffer"
301 (interactive)
302 (if (annotationp xpm-anno)
303 (delete-annotation xpm-anno)))
304
305 (defun xpm-in-body ()
306 (let ((p (point)))
307 (save-excursion
308 (xpm-goto-body-line 0)
309 (> p (point)))))
310
311 (defvar xpm-mode nil)
312 (make-variable-buffer-local 'xpm-mode)
313 (add-minor-mode 'xpm-mode " XPM" nil)
314 (defvar xpm-mode-map (make-keymap))
315
316 (defun xpm-toolbar-select-colour (event chars)
317 "Toolbar button"
318 (let* ((button (event-toolbar-button event))
319 (help (toolbar-button-help-string button)))
320 (message "Toolbar selected %s (%s)" help chars)
321 (setq xpm-palette
322 (mapcar #'(lambda (but)
323 (aset but 2 (not (eq help (aref but 3))))
324 but)
325 xpm-palette)
326 xpm-paint-string chars)
327 (set-specifier left-toolbar (cons (current-buffer) xpm-palette))))
328
329 (defun xpm-mouse-paint (event)
330 (interactive "e")
331 (mouse-set-point event)
332 (if (xpm-in-body)
333 ;; in body, overwrite the paint string where the mouse is clicked
334 (progn
335 (insert xpm-paint-string)
336 (delete-char (length xpm-paint-string)))
337 ;; otherwise, select the color defined by the line where the mouse
338 ;; was clicked
339 (save-excursion
340 (beginning-of-line)
341 (forward-char 1)
342 (setq xpm-paint-string (buffer-substring (point) (1+ (point)))))))
343
344 (defun xpm-mouse-down (event n)
345 ; (interactive "ep")
346 (mouse-set-point event)
347 (if (xpm-in-body)
348 ;; in body, overwrite the paint string where the mouse is clicked
349 (progn
350 (insert xpm-paint-string)
351 (delete-char (length xpm-paint-string))
352 (if xpm-always-update-image
353 (xpm-show-image))
354 (let ((ext (make-extent (1- (point))
355 (+ (1- (point)) xpm-chars-per-pixel)))
356 (pixel-color (assoc xpm-paint-string xpm-pixel-values)))
357 (if pixel-color
358 (set-extent-face ext (cdr pixel-color))
359 (set-extent-face ext 'default))))
360 ;; otherwise, select the color defined by the line where the mouse
361 ;; was clicked
362 (save-excursion
363 (beginning-of-line)
364 (forward-char 1)
365 (setq xpm-paint-string (buffer-substring (point) (1+ (point)))))))
366
367 (defun xpm-mouse-drag (event n timeout)
368 (or timeout
369 (progn
370 (mouse-set-point event)
371 (if (xpm-in-body)
372 ;; Much improved by not using font-lock-mode
373 (or (string= xpm-paint-string
374 (buffer-substring (point)
375 (+ (length xpm-paint-string)
376 (point))))
377 (progn
378 (insert-char (string-to-char xpm-paint-string) 1)
379 ; (insert xpm-paint-string)
380 (delete-char (length xpm-paint-string))
381 (if xpm-always-update-image
382 (xpm-show-image))
383 (let ((ext (make-extent
384 (1- (point))
385 (+ (1- (point)) xpm-chars-per-pixel)))
386 (pixel-color
387 (assoc xpm-paint-string xpm-pixel-values)))
388 (if pixel-color
389 (set-extent-face ext (cdr pixel-color))
390 (set-extent-face ext 'default)))))))))
391
392 (defun xpm-mouse-up (event n)
393 (xpm-show-image))
394
395 ;;;###autoload
396 (defun xpm-mode (&optional arg)
397 "Treat the current buffer as an xpm file and colorize it.
398
399 Shift-button-1 lets you paint by dragging the mouse. Shift-button-1 on a
400 color definition line will change the current painting color to that line's
401 value.
402
403 Characters inserted from the keyboard will NOT be colored properly yet.
404 Use the mouse, or do xpm-init (\\[xpm-init]) after making changes.
405
406 \\[xpm-add-color] Add a new color, prompting for character and value
407 \\[xpm-show-image] show the current image at the top of the buffer
408 \\[xpm-parse-color] parse the current line's color definition and add
409 it to the color table. Provided as a means of changing colors.
410 XPM minor mode bindings:
411 \\{xpm-mode-map}"
412
413 (interactive "P")
414 (setq xpm-mode
415 (if (null arg) (not xpm-mode)
416 (> (prefix-numeric-value arg) 0)))
417 (if xpm-mode
418 (progn
419 (xpm-init)
420 (make-local-variable 'mouse-track-down-hook)
421 (make-local-variable 'mouse-track-drag-hook)
422 (make-local-variable 'mouse-track-up-hook)
423 (make-local-variable 'mouse-track-drag-up-hook)
424 (make-local-variable 'mouse-track-click-hook)
425 (setq mouse-track-down-hook 'xpm-mouse-down)
426 (setq mouse-track-drag-hook 'xpm-mouse-drag)
427 (setq mouse-track-up-hook 'xpm-mouse-up)
428 (setq mouse-track-drag-up-hook 'xpm-mouse-up)
429 (setq mouse-track-click-hook nil)
430 (or (assq 'xpm-mode minor-mode-map-alist)
431 (progn
432 (define-key xpm-mode-map [(control c) r] 'xpm-show-image)
433 (define-key xpm-mode-map [(shift button1)] 'mouse-track)
434 (define-key xpm-mode-map [button1] 'mouse-track-default)
435 (define-key xpm-mode-map [(control c) c] 'xpm-add-color)
436 (define-key xpm-mode-map [(control c) p] 'xpm-parse-color)
437 (setq minor-mode-map-alist (cons (cons 'xpm-mode xpm-mode-map)
438 minor-mode-map-alist)))))))
439
440 (provide 'xpm-mode)
441 ;;; xpm-mode.el ends here