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 
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 
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
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 
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 
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 
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 
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