xref: /plan9/sys/src/cmd/lens.c (revision 5e91980f0bca263e952809e3dc0cfc5dde74b999)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5 
6 enum {
7 	Edge = 5,
8 	Maxmag = 16
9 };
10 
11 enum {
12 	Mzoom,
13 	Munzoom,
14 	Mgrid,
15 	Mredraw,
16 	Mexit
17 };
18 
19 char *menustr[] = {
20 	"zoom",
21 	"unzoom",
22 	"grid",
23 	"redraw",
24 	"exit",
25 	nil
26 };
27 
28 Menu menu = {
29 	menustr,
30 	nil,
31 	-1
32 };
33 
34 Point lastp;
35 Image *red;
36 Image *tmp;
37 Image *grid;
38 Image *chequer;
39 int	screenfd;
40 int	mag = 4;
41 int	showgrid = 0;
42 Rectangle	screenr;
43 uchar	*screenbuf;
44 
45 void	magnify(void);
46 void makegrid(void);
47 
48 void
drawit(void)49 drawit(void)
50 {
51 	Rectangle r;
52 	border(screen, screen->r, Edge, red, ZP);
53 	magnify();
54 	r = insetrect(screen->r, Edge);
55 	draw(screen, r, tmp, nil, tmp->r.min);
56 	flushimage(display, 1);
57 }
58 
59 int bypp;
60 
61 void
main(int argc,char * argv[])62 main(int argc, char *argv[])
63 {
64 	Event e;
65 	char buf[5*12];
66 	ulong chan;
67 	int d;
68 
69 	USED(argc, argv);
70 	if(initdraw(nil, nil, "lens") < 0){
71 		fprint(2, "lens: initdraw failed: %r\n");
72 		exits("initdraw");
73 	}
74 	einit(Emouse|Ekeyboard);
75 	red = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, DRed);
76 	chequer = allocimage(display, Rect(0, 0, 2, 2), GREY1, 1, DBlack);
77 	draw(chequer, Rect(0, 0, 1, 1), display->white, nil, ZP);
78 	draw(chequer, Rect(1, 1, 2, 2), display->white, nil, ZP);
79 	lastp = divpt(addpt(screen->r.min, screen->r.max), 2);
80 	screenfd = open("/dev/screen", OREAD);
81 	if(screenfd < 0){
82 		fprint(2, "lens: can't open /dev/screen: %r\n");
83 		exits("screen");
84 	}
85 	if(read(screenfd, buf, sizeof buf) != sizeof buf){
86 		fprint(2, "lens: can't read /dev/screen: %r\n");
87 		exits("screen");
88 	}
89 	chan = strtochan(buf);
90 	d = chantodepth(chan);
91 	if(d < 8){
92 		fprint(2, "lens: can't handle screen format %11.11s\n", buf);
93 		exits("screen");
94 	}
95 	bypp = d/8;
96 	screenr.min.x = atoi(buf+1*12);
97 	screenr.min.y = atoi(buf+2*12);
98 	screenr.max.x = atoi(buf+3*12);
99 	screenr.max.y = atoi(buf+4*12);
100 	screenbuf = malloc(bypp*Dx(screenr)*Dy(screenr));
101 	if(screenbuf == nil){
102 		fprint(2, "lens: buffer malloc failed: %r\n");
103 		exits("malloc");
104 	}
105 	eresized(0);
106 
107 	for(;;)
108 		switch(event(&e)){
109 		case Ekeyboard:
110 			switch(e.kbdc){
111 			case 'q':
112 			case 0x7f:
113 			case '\04':
114 			caseexit:
115 				exits(nil);
116 			case '=':
117 			case '+':
118 			casezoom:
119 				if(mag < Maxmag){
120 					mag++;
121 					makegrid();
122 					drawit();
123 				}
124 				break;
125 			case 'g':
126 			casegrid:
127 				showgrid = !showgrid;
128 				makegrid();
129 				drawit();
130 				break;
131 			case '-':
132 			case '_':
133 			caseunzoom:
134 				if(mag > 1){
135 					mag--;
136 					makegrid();
137 					drawit();
138 				}
139 				break;
140 			case '.':
141 			case ' ':
142 			caseredraw:
143 				drawit();
144 				break;
145 			case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case'0':
146 				mag = e.kbdc-'0';
147 				if(mag == 0)
148 					mag = 10;
149 				makegrid();
150 				drawit();
151 				break;
152 			}
153 			break;
154 		case Emouse:
155 			if(e.mouse.buttons & 1){
156 				lastp = e.mouse.xy;
157 				drawit();
158 			}
159 			if(e.mouse.buttons & 4)
160 				switch(emenuhit(3, &e.mouse, &menu)){
161 				case Mzoom:
162 					goto casezoom;
163 				case Munzoom:
164 					goto caseunzoom;
165 				case Mgrid:
166 					goto casegrid;
167 				case Mredraw:
168 					goto caseredraw;
169 				case Mexit:
170 					goto caseexit;
171 				}
172 			break;
173 		}
174 }
175 
176 void
makegrid(void)177 makegrid(void)
178 {
179 	int m;
180 	if (grid != nil) {
181 		freeimage(grid);
182 		grid = nil;
183 	}
184 	if (showgrid) {
185 		m = mag;
186 		if (m < 5)
187 			m *= 10;
188 		grid = allocimage(display, Rect(0, 0, m, m),
189 			CHAN2(CGrey, 8, CAlpha, 8), 1, DTransparent);
190 		if (grid != nil){
191 			draw(grid, Rect(0, 0, m, 1), chequer, nil, ZP);
192 			draw(grid, Rect(0, 1, 1, m), chequer, nil, ZP);
193 		}
194 	}
195 }
196 
197 void
eresized(int new)198 eresized(int new)
199 {
200 	if(new && getwindow(display, Refnone) < 0){
201 		fprint(2, "lens: can't reattach to window: %r\n");
202 		exits("attach");
203 	}
204 	freeimage(tmp);
205 	tmp = allocimage(display, Rect(0, 0, Dx(screen->r)-Edge, Dy(screen->r)-Edge+Maxmag), screen->chan, 0, DNofill);
206 	if(tmp == nil){
207 		fprint(2, "lens: allocimage failed: %r\n");
208 		exits("allocimage");
209 	}
210 	drawit();
211 }
212 
213 void
magnify(void)214 magnify(void)
215 {
216 	int x, y, xx, yy, dd, i;
217 	int dx, dy;
218 	int xoff, yoff;
219 	uchar out[8192];
220 	uchar sp[4];
221 
222 	dx = (Dx(tmp->r)+mag-1)/mag;
223 	dy = (Dy(tmp->r)+mag-1)/mag;
224 	xoff = lastp.x-Dx(tmp->r)/(mag*2);
225 	yoff  = lastp.y-Dy(tmp->r)/(mag*2);
226 
227 	yy = yoff;
228 	dd = dy;
229 	if(yy < 0){
230 		dd += dy;
231 		yy = 0;
232 	}
233 	if(yy+dd > Dy(screenr))
234 		dd = Dy(screenr)-yy;
235 	seek(screenfd, 5*12+bypp*yy*Dx(screenr), 0);
236 	if(readn(screenfd, screenbuf+bypp*yy*Dx(screenr), bypp*Dx(screenr)*dd) != bypp*Dx(screenr)*dd){
237 		fprint(2, "lens: can't read screen: %r\n");
238 		return;
239 	}
240 
241 	for(y=0; y<dy; y++){
242 		yy = yoff+y;
243 		if(yy>=0 && yy<Dy(screenr))
244 			for(x=0; x<dx; x++){
245 				xx = xoff+x;
246 				if(xx>=0 && xx<Dx(screenr))	/* snarf pixel at xx, yy */
247 					for(i=0; i<bypp; i++)
248 						sp[i] = screenbuf[bypp*(yy*Dx(screenr)+xx)+i];
249 				else
250 					sp[0] = sp[1] = sp[2] = sp[3] = 0;
251 
252 				for(xx=0; xx<mag; xx++)
253 					if(x*mag+xx < tmp->r.max.x)
254 						for(i=0; i<bypp; i++)
255 							out[(x*mag+xx)*bypp+i] = sp[i];
256 			}
257 		else
258 			memset(out, 0, bypp*Dx(tmp->r));
259 		for(yy=0; yy<mag && y*mag+yy<Dy(tmp->r); yy++){
260 			werrstr("no error");
261 			if(loadimage(tmp, Rect(0, y*mag+yy, Dx(tmp->r), y*mag+yy+1), out, bypp*Dx(tmp->r)) != bypp*Dx(tmp->r)){
262 				exits("load");
263 			}
264 		}
265 	}
266 	if (showgrid && mag && grid)
267 		draw(tmp, tmp->r, grid, nil, mulpt(Pt(xoff, yoff), mag));
268 }
269