source: tags/1.7-appstore/source/cocoa-ide/hemlock/unused/archive/hunk-draw.lisp

Last change on this file was 6567, checked in by Gary Byers, 18 years ago

Move lots of (currently unused, often unlikely to ever be used) stuff to an
archive directory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.6 KB
Line 
1;;; -*- Log: hemlock.log; Package: Hemlock-Internals -*-
2;;;
3;;; **********************************************************************
4;;; This code was written as part of the CMU Common Lisp project at
5;;; Carnegie Mellon University, and has been placed in the public domain.
6;;;
7#+CMU (ext:file-comment
8 "$Header$")
9;;;
10;;; **********************************************************************
11;;;
12;;; Written by Bill Chiles and Rob MacLachlan.
13;;;
14;;; Hemlock screen painting routines for the IBM RT running X.
15;;;
16(in-package :hemlock-internals)
17
18
19;;;; TODO
20
21;; . do away with these bogus macros HUNK-PUT-STRING and HUNK-REPLACE-LINE-STRING.
22
23;; . concentrate these in a single point where we draw a string, so that we
24;; can easily introduce foreground and background colors for syntax
25;; highlighting and neater region highlighting.
26
27;; --GB 2003-05-22
28
29(defparameter hunk-height-limit 80 "Maximum possible height for any hunk.")
30(defparameter hunk-width-limit 200 "Maximum possible width for any hunk.")
31(defparameter hunk-top-border 2 "Clear area at beginning.")
32(defparameter hunk-left-border 10 "Clear area before first character.")
33(defparameter hunk-bottom-border 3 "Minimum Clear area at end.")
34(defparameter hunk-thumb-bar-bottom-border 10
35 "Minimum Clear area at end including room for thumb bar." )
36(defparameter hunk-modeline-top 2 "Extra black pixels above modeline chars.")
37(defparameter hunk-modeline-bottom 2 "Extra black pixels below modeline chars.")
38
39
40
41
42;;;; Character translations for CLX
43
44;;; HEMLOCK-TRANSLATE-DEFAULT.
45;;;
46;;; CLX glyph drawing routines allow for a character translation function. The
47;;; default one takes a string (any kind) or a vector of numbers and slams them
48;;; into the outgoing request buffer. When the argument is a string, it stops
49;;; processing if it sees a character that is not GRAPHIC-CHAR-P. For each
50;;; graphical character, the function ultimately calls CHAR-CODE.
51;;;
52;;; Hemlock only passes simple-strings in, and these can only contain graphical
53;;; characters because of the line image builder, except for one case --
54;;; *line-wrap-char* which anyone can set. Those who want to do evil things
55;;; with this should know what they are doing: if they want a funny glyph as
56;;; a line wrap char, then they should use CODE-CHAR on the font index. This
57;;; allows the following function to translate everything with CHAR-CODE, and
58;;; everybody's happy.
59;;;
60;;; Actually, Hemlock can passes the line string when doing random-typeout which
61;;; does contain ^L's, tabs, etc. Under X10 these came out as funny glyphs,
62;;; and under X11 the output is aborted without this function.
63;;;
64(defun hemlock-translate-default (src src-start src-end font dst dst-start)
65 (declare (simple-string src)
66 (fixnum src-start src-end dst-start)
67 (vector dst)
68 (ignore font))
69 (do ((i src-start (1+ i))
70 (j dst-start (1+ j)))
71 ((>= i src-end) i)
72 (declare (fixnum i j))
73 (setf (aref dst j) (char-code (schar src i)))))
74
75#+clx
76(defvar *glyph-translate-function* #'xlib:translate-default)
77
78
79
80
81;;;; Drawing a line.
82
83;;;; We hack along --GB
84#+clx
85(defun find-color (window color)
86 (let ((ht (or (getf (xlib:window-plist window) :color-hash)
87 (setf (getf (xlib:window-plist window) :color-hash)
88 (make-hash-table :test #'equalp)))))
89 (or (gethash color ht)
90 (setf (gethash color ht) (xlib:alloc-color (xlib:window-colormap window) color)))))
91
92(defparameter *color-map*
93 #("black" "white"
94 "black" "white"
95 "black" "white"
96 "black" "cornflower blue"
97
98 "black" "white"
99 "black" "white"
100 "black" "white"
101 "black" "white"
102
103 "blue4" "white" ;8 = comments
104 "green4" "white" ;9 = strings
105 "red" "white" ;10 = quote
106 "black" "white"
107
108 "black" "white"
109 "black" "white"
110 "black" "white"
111 "black" "white"))
112
113;;; HUNK-PUT-STRING takes a character (x,y) pair and computes at which pixel
114;;; coordinate to draw string with font from start to end.
115;;;
116(defmacro hunk-put-string (x y font string start end)
117 (let ((gcontext (gensym)))
118 `(let ((,gcontext (bitmap-hunk-gcontext hunk)))
119 (xlib:with-gcontext (,gcontext :font ,font)
120 (xlib:draw-image-glyphs
121 (bitmap-hunk-xwindow hunk) ,gcontext
122 (+ hunk-left-border (* ,x (font-family-width font-family)))
123 (+ hunk-top-border (* ,y (font-family-height font-family))
124 (font-family-baseline font-family))
125 ,string :start ,start :end ,end
126 :translate *glyph-translate-function*)))))
127
128(defun hunk-put-string* (hunk x y font-family font string start end)
129 (let ((gcontext (bitmap-hunk-gcontext hunk))
130 (font (svref (font-family-map font-family) font))
131 (fg (find-color (bitmap-hunk-xwindow hunk) (svref *color-map* (* font 2))))
132 (bg (find-color (bitmap-hunk-xwindow hunk) (svref *color-map* (1+ (* font 2))))))
133 (xlib:with-gcontext (gcontext :font font
134 :foreground fg
135 :background bg)
136 (xlib:draw-image-glyphs
137 (bitmap-hunk-xwindow hunk) gcontext
138 (+ hunk-left-border (* x (font-family-width font-family)))
139 (+ hunk-top-border (* y (font-family-height font-family))
140 (font-family-baseline font-family))
141 string :start start :end end
142 :translate *glyph-translate-function*))))
143
144;;; HUNK-REPLACE-LINE-STRING takes a character (x,y) pair and computes at
145;;; which pixel coordinate to draw string with font from start to end. We draw
146;;; the text on a pixmap and later blast it out to avoid line flicker since
147;;; server on the RT is not very clever; it clears the entire line before
148;;; drawing text.
149
150(defun hunk-replace-line-string* (hunk gcontext x y font-family font string start end)
151 (declare (ignore y))
152 (let ((font (svref (font-family-map font-family) font))
153 (fg (find-color (bitmap-hunk-xwindow hunk) (svref *color-map* (* font 2))))
154 (bg (find-color (bitmap-hunk-xwindow hunk) (svref *color-map* (1+ (* font 2))))))
155 (xlib:with-gcontext (gcontext :font font
156 :foreground fg
157 :background bg)
158 (xlib:draw-image-glyphs
159 (hunk-replace-line-pixmap) gcontext
160 (+ hunk-left-border (* x (font-family-width font-family)))
161 (font-family-baseline font-family)
162 string :start start :end end
163 :translate *glyph-translate-function*))))
164
165;;; Hunk-Write-Line -- Internal
166;;;
167;;; Paint a dis-line on a hunk, taking font-changes into consideration.
168;;; The area of the hunk drawn on is assumed to be cleared. If supplied,
169;;; the line is written at Position, and the position in the dis-line
170;;; is ignored.
171;;;
172(defun hunk-write-line (hunk dl &optional (position (dis-line-position dl)))
173 (let* ((font-family (bitmap-hunk-font-family hunk))
174 (chars (dis-line-chars dl))
175 (length (dis-line-length dl)))
176 (let ((last 0)
177 (last-font 0))
178 (do ((change (dis-line-font-changes dl) (font-change-next change)))
179 ((null change)
180 (hunk-put-string* hunk last position font-family last-font chars last length))
181 (let ((x (font-change-x change)))
182 (hunk-put-string* hunk last position font-family last-font chars last x)
183 (setq last x
184 last-font (font-change-font change)) )))))
185
186
187;;; We hack this since the X11 server's aren't clever about DRAW-IMAGE-GLYPHS;
188;;; that is, they literally clear the line, and then blast the new glyphs.
189;;; We don't hack replacing the line when reverse video is turned on because
190;;; this doesn't seem to work too well. Also, hacking replace line on the
191;;; color Megapel display is SLOW!
192;;;
193(defvar *hack-hunk-replace-line* t)
194
195;;; Hunk-Replace-Line -- Internal
196;;;
197;;; Similar to Hunk-Write-Line, but the line need not be clear.
198;;;
199(defun hunk-replace-line (hunk dl &optional
200 (position (dis-line-position dl)))
201 (if *hack-hunk-replace-line*
202 (hunk-replace-line-on-a-pixmap hunk dl position)
203 (old-hunk-replace-line hunk dl position)))
204
205(defun old-hunk-replace-line (hunk dl &optional (position (dis-line-position dl)))
206 (let* ((font-family (bitmap-hunk-font-family hunk))
207 (chars (dis-line-chars dl))
208 (length (dis-line-length dl))
209 (height (font-family-height font-family)) )
210 (let ((last 0)
211 (last-font 0))
212 (do ((change (dis-line-font-changes dl) (font-change-next change)))
213 ((null change)
214 (hunk-put-string* hunk last position font-family last-font chars last length)
215 (let ((dx (+ hunk-left-border
216 (* (font-family-width font-family) length))))
217 (xlib:clear-area (bitmap-hunk-xwindow hunk)
218 :x dx
219 :y (+ hunk-top-border (* position height))
220 :width (- (bitmap-hunk-width hunk) dx)
221 :height height)))
222 (let ((x (font-change-x change)))
223 (hunk-put-string* hunk last position font-family last-font chars last x)
224 (setq last x last-font (font-change-font change)) )))))
225
226(defvar *hunk-replace-line-pixmap* nil)
227
228(defun hunk-replace-line-pixmap ()
229 (if *hunk-replace-line-pixmap*
230 *hunk-replace-line-pixmap*
231 (let* ((hunk (window-hunk *current-window*))
232 (gcontext (bitmap-hunk-gcontext hunk))
233 (screen (xlib:display-default-screen
234 (bitmap-device-display (device-hunk-device hunk))))
235 (height (font-family-height *default-font-family*))
236 (pixmap (xlib:create-pixmap
237 :width (* hunk-width-limit
238 (font-family-width *default-font-family*))
239 :height height :depth (xlib:screen-root-depth screen)
240 :drawable (xlib:screen-root screen))))
241 (xlib:with-gcontext (gcontext :function boole-1
242 :foreground *default-background-pixel*)
243 (xlib:draw-rectangle pixmap gcontext 0 0 hunk-left-border height t))
244 (setf *hunk-replace-line-pixmap* pixmap))))
245
246(defun hunk-replace-line-on-a-pixmap (hunk dl position)
247 (let* ((font-family (bitmap-hunk-font-family hunk))
248 (chars (dis-line-chars dl))
249 (length (dis-line-length dl))
250 (height (font-family-height font-family))
251 (last 0)
252 (last-font 0)
253 (gcontext (bitmap-hunk-gcontext hunk)))
254 (do ((change (dis-line-font-changes dl) (font-change-next change)))
255 ((null change)
256 (hunk-replace-line-string* hunk gcontext last position font-family last-font chars last length)
257 (let* ((dx (+ hunk-left-border
258 (* (font-family-width font-family) length)))
259 (dy (+ hunk-top-border (* position height)))
260 (xwin (bitmap-hunk-xwindow hunk)))
261 (xlib:with-gcontext (gcontext :exposures nil)
262 (xlib:copy-area (hunk-replace-line-pixmap) gcontext
263 0 0 dx height xwin 0 dy))
264 (xlib:clear-area xwin :x dx :y dy
265 :width (- (bitmap-hunk-width hunk) dx)
266 :height height)))
267 (let ((x (font-change-x change)))
268 (hunk-replace-line-string* hunk gcontext last position font-family last-font chars last x)
269 (setq last x last-font (font-change-font change))))))
270
271
272;;; HUNK-REPLACE-MODELINE sets the entire mode line to the the foreground
273;;; color, so the initial bits where no characters go also is highlighted.
274;;; Then the text is drawn background on foreground (hightlighted). This
275;;; function assumes that BITMAP-HUNK-MODELINE-POS will not return nil;
276;;; that is, there is a modeline. This function should assume the gcontext's
277;;; font is the default font of the hunk. We must LET bind the foreground and
278;;; background values before entering XLIB:WITH-GCONTEXT due to a non-obvious
279;;; or incorrect implementation.
280;;;
281(defun hunk-replace-modeline (hunk)
282 (let* ((dl (bitmap-hunk-modeline-dis-line hunk))
283 (font-family (bitmap-hunk-font-family hunk))
284 (default-font (svref (font-family-map font-family) 0))
285 (modeline-pos (bitmap-hunk-modeline-pos hunk))
286 (xwindow (bitmap-hunk-xwindow hunk))
287 (gcontext (bitmap-hunk-gcontext hunk)))
288 (xlib:draw-rectangle xwindow gcontext 0 modeline-pos
289 (bitmap-hunk-width hunk)
290 (+ hunk-modeline-top hunk-modeline-bottom
291 (font-family-height font-family))
292 t)
293 (xlib:with-gcontext (gcontext :foreground
294 (xlib:gcontext-background gcontext)
295 :background
296 (xlib:gcontext-foreground gcontext)
297 :font default-font)
298 (xlib:draw-image-glyphs xwindow gcontext hunk-left-border
299 (+ modeline-pos hunk-modeline-top
300 (font-family-baseline font-family))
301 (dis-line-chars dl)
302 :end (dis-line-length dl)
303 :translate *glyph-translate-function*))))
304
305
306
307;;;; Cursor/Border color manipulation.
308
309;;; *hemlock-listener* is set to t by default because we can't know from X
310;;; whether we come up with the pointer in our window. There is no initial
311;;; :enter-window event. Defaulting this to nil causes the cursor to be hollow
312;;; when the window comes up under the mouse, and you have to know how to fix
313;;; it. Defaulting it to t causes the cursor to always come up full, as if
314;;; Hemlock is the X listener, but this recovers naturally as you move into the
315;;; window. This also coincides with Hemlock's border coming up highlighted,
316;;; even when Hemlock is not the listener.
317;;;
318(defvar *hemlock-listener* t
319 "Highlight border when the cursor is dropped and Hemlock can receive input.")
320(defvar *current-highlighted-border* nil
321 "When non-nil, the bitmap-hunk with the highlighted border.")
322
323(defvar *hunk-cursor-x* 0 "The current cursor X position in pixels.")
324(defvar *hunk-cursor-y* 0 "The current cursor Y position in pixels.")
325(defvar *cursor-hunk* nil "Hunk the cursor is displayed on.")
326(defvar *cursor-dropped* nil) ; True if the cursor is currently displayed.
327
328;;; HUNK-SHOW-CURSOR locates the cursor at character position (x,y) in hunk.
329;;; If the cursor is currently displayed somewhere, then lift it, and display
330;;; it at its new location.
331;;;
332(defun hunk-show-cursor (hunk x y)
333 (unless (and (= x *hunk-cursor-x*)
334 (= y *hunk-cursor-y*)
335 (eq hunk *cursor-hunk*))
336 (let ((cursor-down *cursor-dropped*))
337 (when cursor-down (lift-cursor))
338 (setf *hunk-cursor-x* x)
339 (setf *hunk-cursor-y* y)
340 (setf *cursor-hunk* hunk)
341 (when cursor-down (drop-cursor)))))
342
343;;; FROB-CURSOR is the note-read-wait method for bitmap redisplay. We
344;;; show a cursor and highlight the listening window's border when waiting
345;;; for input.
346;;;
347(defun frob-cursor (on)
348 (if on (drop-cursor) (lift-cursor)))
349
350(declaim (special *default-border-pixmap* *highlight-border-pixmap*))
351
352;;; DROP-CURSOR and LIFT-CURSOR are separate functions from FROB-CURSOR
353;;; because they are called a couple places (e.g., HUNK-EXPOSED-REGION
354;;; and SMART-WINDOW-REDISPLAY). When the cursor is being dropped, since
355;;; this means Hemlock is listening in the *cursor-hunk*, make sure the
356;;; border of the window is highlighted as well.
357;;;
358(defun drop-cursor ()
359 (unless *cursor-dropped*
360 (unless *hemlock-listener* (cursor-invert-center))
361 (cursor-invert)
362 (when *hemlock-listener*
363 (cond (*current-highlighted-border*
364 (unless (eq *current-highlighted-border* *cursor-hunk*)
365 (setf (xlib:window-border
366 (window-group-xparent
367 (bitmap-hunk-window-group *current-highlighted-border*)))
368 *default-border-pixmap*)
369 (setf (xlib:window-border
370 (window-group-xparent
371 (bitmap-hunk-window-group *cursor-hunk*)))
372 *highlight-border-pixmap*)
373 ;; For complete gratuitous pseudo-generality, should force
374 ;; output on *current-highlighted-border* device too.
375 (xlib:display-force-output
376 (bitmap-device-display (device-hunk-device *cursor-hunk*)))))
377 (t (setf (xlib:window-border
378 (window-group-xparent
379 (bitmap-hunk-window-group *cursor-hunk*)))
380 *highlight-border-pixmap*)
381 (xlib:display-force-output
382 (bitmap-device-display (device-hunk-device *cursor-hunk*)))))
383 (setf *current-highlighted-border* *cursor-hunk*))
384 (setq *cursor-dropped* t)))
385
386;;;
387(defun lift-cursor ()
388 (when *cursor-dropped*
389 (unless *hemlock-listener* (cursor-invert-center))
390 (cursor-invert)
391 (setq *cursor-dropped* nil)))
392
393
394(defun cursor-invert-center ()
395 (let ((family (bitmap-hunk-font-family *cursor-hunk*))
396 (gcontext (bitmap-hunk-gcontext *cursor-hunk*)))
397 (xlib:with-gcontext (gcontext :function boole-xor
398 :foreground *foreground-background-xor*)
399 (xlib:draw-rectangle (bitmap-hunk-xwindow *cursor-hunk*)
400 gcontext
401 (+ hunk-left-border
402 (* *hunk-cursor-x* (font-family-width family))
403 (font-family-cursor-x-offset family)
404 1)
405 (+ hunk-top-border
406 (* *hunk-cursor-y* (font-family-height family))
407 (font-family-cursor-y-offset family)
408 1)
409 (- (font-family-cursor-width family) 2)
410 (- (font-family-cursor-height family) 2)
411 t)))
412 (xlib:display-force-output
413 (bitmap-device-display (device-hunk-device *cursor-hunk*))))
414
415(defun cursor-invert ()
416 (let ((family (bitmap-hunk-font-family *cursor-hunk*))
417 (gcontext (bitmap-hunk-gcontext *cursor-hunk*)))
418 (xlib:with-gcontext (gcontext :function boole-xor
419 :foreground *foreground-background-xor*)
420 (xlib:draw-rectangle (bitmap-hunk-xwindow *cursor-hunk*)
421 gcontext
422 (+ hunk-left-border
423 (* *hunk-cursor-x* (font-family-width family))
424 (font-family-cursor-x-offset family))
425 (+ hunk-top-border
426 (* *hunk-cursor-y* (font-family-height family))
427 (font-family-cursor-y-offset family))
428 (font-family-cursor-width family)
429 (font-family-cursor-height family)
430 t)))
431 (xlib:display-force-output
432 (bitmap-device-display (device-hunk-device *cursor-hunk*))))
433
434
435
436
437;;;; Clearing and Copying Lines.
438
439(defun hunk-clear-lines (hunk start count)
440 (let ((height (font-family-height (bitmap-hunk-font-family hunk))))
441 (xlib:clear-area (bitmap-hunk-xwindow hunk)
442 :x 0 :y (+ hunk-top-border (* start height))
443 :width (bitmap-hunk-width hunk)
444 :height (* count height))))
445
446(defun hunk-copy-lines (hunk src dst count)
447 (let ((height (font-family-height (bitmap-hunk-font-family hunk)))
448 (xwindow (bitmap-hunk-xwindow hunk)))
449 (xlib:copy-area xwindow (bitmap-hunk-gcontext hunk)
450 0 (+ hunk-top-border (* src height))
451 (bitmap-hunk-width hunk) (* height count)
452 xwindow 0 (+ hunk-top-border (* dst height)))))
453
454
455
456
457;;;; Drawing bottom border meter.
458
459;;; HUNK-DRAW-BOTTOM-BORDER assumes eight-character-space tabs. The LOGAND
460;;; calls in the loop are testing for no remainder when dividing by 8, 4,
461;;; and other. This lets us quickly draw longer notches at tab stops and
462;;; half way in between. This function assumes that
463;;; BITMAP-HUNK-MODELINE-POS will not return nil; that is, that there is a
464;;; modeline.
465;;;
466(defun hunk-draw-bottom-border (hunk)
467 (when (bitmap-hunk-thumb-bar-p hunk)
468 (let* ((xwindow (bitmap-hunk-xwindow hunk))
469 (gcontext (bitmap-hunk-gcontext hunk))
470 (modeline-pos (bitmap-hunk-modeline-pos hunk))
471 (font-family (bitmap-hunk-font-family hunk))
472 (font-width (font-family-width font-family)))
473 (xlib:clear-area xwindow :x 0 :y (- modeline-pos
474 hunk-thumb-bar-bottom-border)
475 :width (bitmap-hunk-width hunk)
476 :height hunk-bottom-border)
477 (let ((x (+ hunk-left-border (ash font-width -1)))
478 (y7 (- modeline-pos 7))
479 (y5 (- modeline-pos 5))
480 (y3 (- modeline-pos 3)))
481 (dotimes (i (bitmap-hunk-char-width hunk))
482 (cond ((zerop (logand i 7))
483 (xlib:draw-rectangle xwindow gcontext
484 x y7 (if (= i 80) 2 1) 7 t))
485 ((zerop (logand i 3))
486 (xlib:draw-rectangle xwindow gcontext x y5 1 5 t))
487 (t
488 (xlib:draw-rectangle xwindow gcontext x y3 1 3 t)))
489 (incf x font-width))))))
490
491;; $Log$
492;; Revision 1.1 2003/10/19 08:57:15 gb
493;; Initial revision
494;;
495;; Revision 1.1.2.2 2003/09/18 13:40:16 gb
496;; Conditionalize for #-CLX, a little more.
497;;
498;; Revision 1.1.2.1 2003/08/10 19:11:27 gb
499;; New files, imported from upstream CVS as of 03/08/09.
500;;
501;; Revision 1.4 2003/08/05 19:54:17 gilbert
502;; - did away with some macros
503;; - invested in a left margin for added readability of hemlock frames.
504;;
Note: See TracBrowser for help on using the repository browser.