1 /* @(#)graphics3.c 1.4 05/29/84
2 *
3 * Copyright -C- 1982 Barry S. Roitblat
4 *
5 * This file contains additional routines for implementing graphics
6 * primitives for the gremlin picture editor
7 */
8
9 #include "gremlin.h"
10 #include <sys/types.h>
11 #include <sys/timeb.h>
12 #include <signal.h>
13 #include <sys/time.h>
14
15 /* imports from graphics1.c */
16
17 extern GRsetwmask();
18 extern int curx, cury, rmask;
19 extern FILE *display;
20 extern GRClear();
21
22 /* library routines */
23
24 extern ftime();
25
GREnableTablet()26 GREnableTablet()
27
28 /*---------------------------------------------------------
29 * This routine enables the graphics tablet.
30 *
31 * Results: None.
32 *
33 * Side Effects:
34 * The tablet cursor is enabled on the AED. This will cause characters
35 * to be sent over the serial line whenever a button on the cursor is
36 * pushed. After calling this routine, the routine GrGetButton may
37 * be called to wait for the next button to be pushed.
38 *
39 * Design:
40 * Note: the AED really messes up with the cursor, because it
41 * continually overwrites CAP with cursor coordinates. Thus the
42 * cursor must disabled before doing ANYTHING to the AED.
43 *---------------------------------------------------------
44 */
45
46 {
47 GRsetwmask(127); /* don't write cursor on grid layer */
48 fputs("3:", display);
49 (void) fflush(display);
50 }
51
GRDisableTablet()52 GRDisableTablet()
53
54 /*---------------------------------------------------------
55 * This routine disables the graphics tablet so that other things may
56 * be done with the AED.
57 *
58 * Results: None.
59 * Side Effects: The tablet is disabled.
60 *---------------------------------------------------------
61 */
62
63 {
64 putc('3', display);
65 putc('\0', display);
66 (void) fflush(display);
67 curx = cury = -1;
68 }
69
70
71 #define MINTIME 100 /* 100 milliseconds */
72
73 int
GRGetButton(stream,px,py)74 GRGetButton(stream, px, py)
75 FILE *stream; /* File from which AED chars. can be read */
76 int *px; /* Address of a word to hold x-coordinate */
77 int *py; /* Address of word to hold y-coorinate */
78
79 /*---------------------------------------------------------
80 * This routine waits for cursor input.
81 *
82 * Results:
83 * The return value is the number of the button that was pushed.
84 * If an error occurs while reading from the stream, -1 is returned.
85 *
86 * Side Effects:
87 * The integers pointed to by px and py are filled in with the
88 * x- and y-coordinates of the cursor at the time the button
89 * was pushed.
90 *
91 * Design:
92 * This is tricky. The AED apparently sends bogus button data at
93 * random times. It can usually be distinguished by the presence
94 * of an illegal button number. We must pick out such data and throw
95 * it away.
96 *
97 * For systems up to 4.1BSD (characterized by the presence of the
98 * SIGTINT signal) the routine waits for cursor input.
99 * For 4.2BSD and beyond, the routine gives an error of -4 if input
100 * is not immediately available (it expects to be called only when
101 * input is available).
102 *---------------------------------------------------------
103 */
104
105 {
106 int button;
107 struct timeval selectpoll;
108 static unsigned long time, lastime = 0;
109 struct timeb tp;
110 static char line1[100];
111
112 selectpoll.tv_sec = 0l;
113 selectpoll.tv_usec = 0l;
114 while (TRUE)
115 {
116
117 #ifndef SIGTINT
118 button = 1 << fileno(stream);
119 if (select(20, &button, 0, 0, &selectpoll) <= 0) return -4;
120 #endif
121
122 if (fgets(line1, 99, stream) == NULL) return -1;
123 if (line1[0] != ':') continue;
124 (void) sscanf(&(line1[1]), "%d", &button);
125 if (fgets(line1, 99, stream) == NULL) return -2;
126 (void) sscanf (line1, "%d", px);
127 if (fgets(line1, 99, stream) == NULL) return -3;
128 (void) sscanf (line1, "%d", py);
129
130 /* wait for minimum duration before accepting */
131 /* new button to debounce the cursor */
132
133 ftime(&tp);
134 time = 1000 * tp.time + tp.millitm;
135 if ((time - lastime) < MINTIME ) continue;
136 lastime = time;
137
138 if (button == 2) return 1;
139 if (button == 4) return 2;
140 if (button == 8) return 3;
141 if (button == 1) return 0;
142 }
143 }
144
145
146
GRSetGrid(x1,y1,x2,y2,size)147 GRSetGrid(x1, y1, x2, y2, size)
148 int x1, y1, x2, y2, size;
149 /*
150 * This routine sets the grid according to the paramaters
151 * (lower left and upper right corners, and spacing) supplied. The
152 * grid is written to the appropriate memory plane but will not be
153 * displayed unless that plane has been (Read) enabled.
154 */
155
156 {
157 int i, start;
158 POINT end1, end2;
159
160 GRClear(gridmask);
161 GRsetwmask(gridmask);
162 end1.y = (float) y1;
163 end2.y = (float) y2;
164 start = ((x1 + size - 1) - ((x1 + size - 1) % size));
165
166 /* start forces the lines to be drawn on pixel
167 boundaries evenly divisible by size */
168
169 for (i=start; i<=x2; i+=size)
170 {
171 end1.x = end2.x = (float) i;
172 GRVector(&end1, &end2, gridstyle);
173 } /* end for */;
174 end1.x = (float) x1;
175 end2.x = (float) x2;
176 start = ((y1 + size - 1) - ((y1 + size - 1) % size));
177 for (i=start; i<=y2; i+=size)
178 {
179 end1.y = end2.y = (float) i;
180 GRVector(&end1, &end2, gridstyle);
181 } /* end for */;
182 } /* end SetGrid */;
183
184
GRSetRead(mask)185 GRSetRead(mask)
186 int mask;
187 /*
188 * This routine sets the read mask.
189 */
190
191 {
192 #ifndef FASTIO
193 char s1[3], s2[3], s3[3], s4[3];
194 #endif
195
196 rmask = mask;
197
198 #ifndef FASTIO
199 GRchex(rmask,s1,2);
200 GRchex(rmask1,s2,2);
201 GRchex(rmask2,s3,2);
202 GRchex(rmask3,s4,2);
203 fprintf(display,"M%s%s%s%s", s1, s2, s3, s4);
204 #else
205 putc('M',display);
206 putc(rmask,display);
207 putc(rmask1,display);
208 putc(rmask2,display);
209 putc(rmask3,display);
210 #endif
211
212 (void) fflush(display);
213 } /* end SetRead */
214
215
GRDisplayGrid()216 GRDisplayGrid()
217 /*
218 * This routine displays the grid created by setgrid by enabling
219 * the appropriate read layer.
220 */
221
222 {
223 GRSetRead(rmask | gridmask);
224 } /* end DisplayGrid */
225
GRBlankGrid()226 GRBlankGrid()
227 /*
228 * This routine assures that the grid is not displayed by
229 * setting the read mask to disable the grid layer.
230 */
231
232 {
233
234 GRSetRead(rmask & ~gridmask);
235 } /* end BlankGrid */
236
237