-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdrawing.scm
358 lines (314 loc) · 12.4 KB
/
drawing.scm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
;;; ezd - easy drawing for X11.
;;;
;;; A DRAWING contains a set of graphical objects. These objects are displayed
;;; by drawing them with a view into a window. The view into a window also
;;; allows events to be mapped back into the drawing.
;* Copyright 1990-1993 Digital Equipment Corporation
;* All Rights Reserved
;*
;* Permission to use, copy, and modify this software and its documentation is
;* hereby granted only under the following terms and conditions. Both the
;* above copyright notice and this permission notice must appear in all copies
;* of the software, derivative works or modified versions, and any portions
;* thereof, and both notices must appear in supporting documentation.
;*
;* Users of this software agree to the terms and conditions set forth herein,
;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
;* right and license under any changes, enhancements or extensions made to the
;* core functions of the software, including but not limited to those affording
;* compatibility with other hardware or software environments, but excluding
;* applications which incorporate this software. Users further agree to use
;* their best efforts to return to Digital any such changes, enhancements or
;* extensions that they make and inform Digital of noteworthy uses of this
;* software. Correspondence should be provided to Digital at:
;*
;* Director of Licensing
;* Western Research Laboratory
;* Digital Equipment Corporation
;* 250 University Avenue
;* Palo Alto, California 94301
;*
;* This software may be distributed (but not offered for sale or transferred
;* for compensation) to third parties, provided such third parties agree to
;* abide by the terms and conditions of this notice.
;*
;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
;* SOFTWARE.
;;; A DRAWING is a structured object consisting of the following fields:
;;;
;;; NAME symbolic name of the drawing.
;;; HEAD head of the list of objects in the drawing. Since this
;;; list is in drawing order, the objects at the "bottom"
;;; of the drawing are at the head of the list.
;;; TAIL tail of the list of objects in the drawing.
;;; ADDED-HEAD head of the list of recent additions to the drawing.
;;; ADDED-TAIL tail of the list of recent additions to the drawing.
;;; ZMOTION objects have been rearranged in the drawing.
;;; DAMAGED head of the list of functions computing bounding boxes
;;; describing objects damaged in the drawing.
;;; CLEARED boolean indicating that the drawing has been cleared.
;;; IS-CLEAR boolean indicating that nothing but clear objects have
;;; been drawn in the drawing.
;;; WINDOW-WATCH list of object names that may have an object specific
;;; event handler for RESIZE, EXPOSE, OVERLAY, or VISIBLE
;;; events.
;;; EVENTS list of events that are for the object "*".
(define-structure drawing
name
(head '())
(tail '())
(added-head '())
(added-tail '())
(zmotion #f)
(damaged '())
(cleared #f)
(is-clear #t)
(window-watch '())
(events (let* ((name (drawing-name self))
(x (assoc name *drawings*)))
(if x (set! *drawings* (delete x *drawings*)))
(set! *drawings* (cons (list name self) *drawings*))
'())))
(define-in-line-structure-access drawing
name
head
tail
added-head
added-tail
zmotion
damaged
cleared
is-clear
window-watch
events)
;;; A list of lists associating the name of each drawing with the data
;;; structure is maintained in the global *DRAWINGS*.
(define *drawings* '())
;;; A drawing name can be converted to the appropriate data structure by the
;;; function NAME->DRAWING.
(define (name->drawing name)
(let ((x (assoc name *drawings*)))
(if x (cadr x) (error 'name->drawing "undefined DRAWING: ~s" name))))
;;; Boolean to test if a drawing already exists.
(define (drawing-exists? name)
(if (assoc name *drawings*) #t #f))
;;; The name of an object in the current drawing is coverted to the graphic
;;; structure representing it by the following function. It is an error to
;;; look up a non-existent object.
(define (name->graphic name)
(let ((g (getprop name (drawing-name *current-drawing*))))
(if g g (error 'NAME->GRAPHIC "OBJECT does not exist: ~s" name))))
;;; An object is verified to be the name of a graphic object by the following
;;; procedure.
(define (name-of-graphic? name)
(and *current-drawing*
(symbol? name)
(getprop name (drawing-name *current-drawing*))))
;;; Most drawing commands have an implied argument, the current drawing. The
;;; global *CURRENT-DRAWING* represents it.
(define *current-drawing* #f)
;;; The ezd command SET-DRAWING is used to set the current drawing. If a
;;; drawing by that name does not exist, then one is created.
(define (set-drawing name)
(let ((drawing (if (drawing-exists? name)
(name->drawing name)
(make-drawing name))))
(set! *current-drawing* drawing)))
(define-ezd-command
`(set-drawing ,symbol?)
"(set-drawing drawing-name)"
set-drawing)
;;; The ezd commands SAVE-DRAWING and RESTORE-DRAWING push and pop the current
;;; drawing on a stack.
(define *saved-drawings* '())
(define-ezd-command
`(save-drawing)
"(save-drawing)"
(lambda ()
(if *current-drawing*
(set! *saved-drawings*
(cons *current-drawing* *saved-drawings*)))))
(define-ezd-command
`(restore-drawing)
"(restore-drawing)"
(lambda ()
(unless (null? *saved-drawings*)
(set! *current-drawing* (car *saved-drawings*))
(set! *saved-drawings* (cdr *saved-drawings*)))))
;;; A drawing is cleared by the following procedure.
(define (drawing-clear drawing)
(let ((dname (drawing-name drawing)))
(for-each
(lambda (g)
(let ((object-name (graphic-name g)))
(if object-name
(putprop object-name dname #f))))
(drawing-head drawing))
(drawing-head! drawing '())
(drawing-tail! drawing '())
(drawing-added-head! drawing '())
(drawing-added-tail! drawing '())
(drawing-zmotion! drawing #f)
(drawing-damaged! drawing '())
(drawing-cleared! drawing #t)
(drawing-is-clear! drawing #t)
(drawing-window-watch! drawing '())
(drawing-events! drawing '())
(set! *update-display* #t)))
;;; The currently selected drawing is cleared by the ezd command CLEAR.
(define-ezd-command
'(clear)
"(clear)"
(lambda () (if *current-drawing* (drawing-clear *current-drawing*))))
;;; Graphic objects are moved to either the top or the bottom of the current
;;; drawing or relative to another object by the following procedure and
;;; commands.
(define (float/sink-object drawing obj-name ref-name float)
(let ((object (name->graphic obj-name))
(reference (and ref-name (name->graphic ref-name)))
(prev-reference (not ref-name))
(object-deleted #f))
;;; Delete object and correct pointers, find reference object.
(let loop ((prev #t) (gl (drawing-head drawing)))
(if (pair? gl)
(let ((g (car gl)))
(cond ((and (eq? g object)
(not (eq? (drawing-head drawing)
(drawing-tail drawing))))
(let ((oh (drawing-head drawing))
(ot (drawing-tail drawing))
(oah (drawing-added-head drawing))
(oat (drawing-added-tail drawing)))
(if (eq? oh gl)
(drawing-head! drawing (cdr gl)))
(if (eq? ot gl)
(if (eq? ot oh)
(drawing-tail! drawing '())
(drawing-tail! drawing prev)))
(if (eq? oah gl)
(drawing-added-head! drawing (cdr gl)))
(if (eq? oat gl)
(if (eq? oat oah)
(drawing-added-tail! drawing '())
(drawing-added-tail! drawing prev)))
(if (pair? prev) (set-cdr! prev (cdr gl)))
(set! object-deleted #t)
(if (not prev-reference)
(loop prev (cdr gl)))))
((eq? g reference)
(set! prev-reference prev)
(if (not object-deleted) (loop gl (cdr gl))))
(else (loop gl (cdr gl)))))))
;;; Insert object relative to reference object and correct pointers.
(let ((oh (drawing-head drawing))
(ot (drawing-tail drawing))
(oah (drawing-added-head drawing))
(oat (drawing-added-tail drawing))
(lob (list object)))
(if float
(cond ((pair? prev-reference)
(set-cdr! lob (cddr prev-reference))
(set-cdr! (cdr prev-reference) lob))
((and (eq? prev-reference #t) ref-name)
(set-cdr! lob (cdr oh))
(set-cdr! oh lob))
(else (set-cdr! ot lob)
(drawing-tail! drawing lob)))
(cond ((pair? prev-reference)
(set-cdr! lob (cdr prev-reference))
(set-cdr! prev-reference lob))
(else (drawing-head! drawing (cons object oh)))))
(if (eq? oh oah)
(drawing-added-head! drawing (drawing-head drawing)))
(if (eq? ot oat)
(drawing-added-tail! drawing (drawing-tail drawing))))
;;; Mark area contained the moved object as damaged.
(if *clean-mouse-window*
(for-each (lambda (v)
(if (eq? (view-drawing v) drawing)
(set! *clean-mouse-window* #f)))
(window-views *mouse-window*)))
(drawing-damaged! drawing (cons (graphic-compute-bb object)
(drawing-damaged drawing)))
(drawing-zmotion! drawing #t)
(set! *update-display* #t)))
;;; Command parsers and definition.
(define name-of-graphic1? #f)
(define name-of-graphic2?
(let ((name-of-first #f))
(set! name-of-graphic1?
(lambda (x)
(if (name-of-graphic? x)
(begin (set! name-of-first x) #t)
#f)))
(lambda (x) (and (name-of-graphic? x) (not (eq? x name-of-first))))))
(define-ezd-command
`(float ,name-of-graphic1? (optional ,name-of-graphic2?))
"(float object-name [object-name])"
(lambda (o-name1 o-name2)
(float/sink-object *current-drawing* o-name1 o-name2 #t)))
(define-ezd-command
`(sink ,name-of-graphic1? (optional ,name-of-graphic2?))
"(sink object-name [object-name])"
(lambda (o-name1 o-name2)
(float/sink-object *current-drawing* o-name1 o-name2 #f)))
;;; A graphic object is added to a drawing by the following procedure.
(define (drawing-add drawing graphic)
(let ((name (drawing-name drawing))
(object-name (graphic-name graphic)))
(define (add-to-drawing)
(let ((tail (drawing-tail drawing))
(added-tail (drawing-added-tail drawing))
(graphic-list (list graphic)))
(if (null? tail)
(drawing-head! drawing graphic-list)
(set-cdr! tail graphic-list))
(drawing-tail! drawing graphic-list)
(if (null? added-tail)
(drawing-added-head! drawing graphic-list)
(set-cdr! added-tail graphic-list))
(drawing-added-tail! drawing graphic-list)))
(define (graphic-damaged g)
(drawing-damaged! drawing
(cons (graphic-compute-bb g) (drawing-damaged drawing))))
(if (and (drawing-is-clear drawing)
(not (eq? (graphic-xdraw graphic) draw-clear)))
(drawing-is-clear! drawing #f))
(if *clean-mouse-window*
(for-each (lambda (v)
(if (eq? (view-drawing v) drawing)
(set! *clean-mouse-window* #f)))
(window-views *mouse-window*)))
(if object-name
(let ((old-graphic (getprop object-name name)))
(if old-graphic
;;; Object is being replaced by a new one.
(let ((old-events (graphic-events old-graphic)))
(graphic-damaged old-graphic)
(graphic-damaged graphic)
(set-graphic! old-graphic graphic)
(graphic-events! old-graphic old-events))
(begin (putprop object-name name graphic)
(add-to-drawing))))
(add-to-drawing))
(set! *update-display* #t)))
;;; Module reset/initialization.
(define (drawing-module-init)
(for-each
(lambda (name-drawing)
(for-each
(lambda (graphic)
(let ((name (graphic-name graphic)))
(if name
(putprop name (car name-drawing) #f))))
(drawing-head (cadr name-drawing))))
*drawings*)
(set! *drawings* '())
(set! *saved-drawings* '())
(set! *current-drawing* #f))