xref: /plan9/sys/src/cmd/tweak.c (revision bacfa46c74e1c310aff15aef9cb6bc4e6302513a)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <cursor.h>
57dd7cddfSDavid du Colombier #include <event.h>
63e12c5d1SDavid du Colombier #include <bio.h>
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier typedef struct	Thing	Thing;
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier struct Thing
113e12c5d1SDavid du Colombier {
127dd7cddfSDavid du Colombier 	Image	*b;
133e12c5d1SDavid du Colombier 	Subfont 	*s;
143e12c5d1SDavid du Colombier 	char		*name;	/* file name */
153e12c5d1SDavid du Colombier 	int		face;		/* is 48x48 face file or cursor file*/
163e12c5d1SDavid du Colombier 	Rectangle r;		/* drawing region */
173e12c5d1SDavid du Colombier 	Rectangle tr;		/* text region */
183e12c5d1SDavid du Colombier 	Rectangle er;		/* entire region */
193e12c5d1SDavid du Colombier 	long		c;		/* character number in subfont */
203e12c5d1SDavid du Colombier 	int		mod;	/* modified */
213e12c5d1SDavid du Colombier 	int		mag;		/* magnification */
223e12c5d1SDavid du Colombier 	Rune		off;		/* offset for subfont indices */
233e12c5d1SDavid du Colombier 	Thing	*parent;	/* thing of which i'm an edit */
243e12c5d1SDavid du Colombier 	Thing	*next;
253e12c5d1SDavid du Colombier };
263e12c5d1SDavid du Colombier 
273e12c5d1SDavid du Colombier enum
283e12c5d1SDavid du Colombier {
293e12c5d1SDavid du Colombier 	Border	= 1,
303e12c5d1SDavid du Colombier 	Up		= 1,
313e12c5d1SDavid du Colombier 	Down	= 0,
323e12c5d1SDavid du Colombier 	Mag		= 4,
333e12c5d1SDavid du Colombier 	Maxmag	= 10,
343e12c5d1SDavid du Colombier };
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier enum
373e12c5d1SDavid du Colombier {
387dd7cddfSDavid du Colombier 	NORMAL	=0,
397dd7cddfSDavid du Colombier 	FACE	=1,
407dd7cddfSDavid du Colombier 	CURSOR	=2
417dd7cddfSDavid du Colombier };
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier enum
447dd7cddfSDavid du Colombier {
453e12c5d1SDavid du Colombier 	Mopen,
463e12c5d1SDavid du Colombier 	Mread,
473e12c5d1SDavid du Colombier 	Mwrite,
483e12c5d1SDavid du Colombier 	Mcopy,
493e12c5d1SDavid du Colombier 	Mchar,
507dd7cddfSDavid du Colombier 	Mpixels,
513e12c5d1SDavid du Colombier 	Mclose,
523e12c5d1SDavid du Colombier 	Mexit,
533e12c5d1SDavid du Colombier };
543e12c5d1SDavid du Colombier 
557dd7cddfSDavid du Colombier enum
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier 	Blue	= 54,
587dd7cddfSDavid du Colombier };
593e12c5d1SDavid du Colombier 
603e12c5d1SDavid du Colombier char	*menu3str[] = {
613e12c5d1SDavid du Colombier 	[Mopen]	"open",
623e12c5d1SDavid du Colombier 	[Mread]	"read",
633e12c5d1SDavid du Colombier 	[Mwrite]	"write",
643e12c5d1SDavid du Colombier 	[Mcopy]	"copy",
653e12c5d1SDavid du Colombier 	[Mchar]	"char",
667dd7cddfSDavid du Colombier 	[Mpixels]	"pixels",
673e12c5d1SDavid du Colombier 	[Mclose]	"close",
683e12c5d1SDavid du Colombier 	[Mexit]	"exit",
693e12c5d1SDavid du Colombier 	0,
703e12c5d1SDavid du Colombier };
713e12c5d1SDavid du Colombier 
723e12c5d1SDavid du Colombier Menu	menu3 = {
733e12c5d1SDavid du Colombier 	menu3str
743e12c5d1SDavid du Colombier };
753e12c5d1SDavid du Colombier 
763e12c5d1SDavid du Colombier Cursor sweep0 = {
773e12c5d1SDavid du Colombier 	{-7, -7},
783e12c5d1SDavid du Colombier 	{0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
793e12c5d1SDavid du Colombier 	 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
803e12c5d1SDavid du Colombier 	 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0,
813e12c5d1SDavid du Colombier 	 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0},
823e12c5d1SDavid du Colombier 	{0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
833e12c5d1SDavid du Colombier 	 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x7F, 0xFE,
843e12c5d1SDavid du Colombier 	 0x7F, 0xFE, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
853e12c5d1SDavid du Colombier 	 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00}
863e12c5d1SDavid du Colombier };
873e12c5d1SDavid du Colombier 
883e12c5d1SDavid du Colombier Cursor box = {
893e12c5d1SDavid du Colombier 	{-7, -7},
903e12c5d1SDavid du Colombier 	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
913e12c5d1SDavid du Colombier 	 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
923e12c5d1SDavid du Colombier 	 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
933e12c5d1SDavid du Colombier 	 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
943e12c5d1SDavid du Colombier 	{0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
953e12c5d1SDavid du Colombier 	 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
963e12c5d1SDavid du Colombier 	 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
973e12c5d1SDavid du Colombier 	 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00}
983e12c5d1SDavid du Colombier };
993e12c5d1SDavid du Colombier 
1003e12c5d1SDavid du Colombier Cursor sight = {
1013e12c5d1SDavid du Colombier 	{-7, -7},
1023e12c5d1SDavid du Colombier 	{0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
1033e12c5d1SDavid du Colombier 	 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
1043e12c5d1SDavid du Colombier 	 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
1053e12c5d1SDavid du Colombier 	 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,},
1063e12c5d1SDavid du Colombier 	{0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
1073e12c5d1SDavid du Colombier 	 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
1083e12c5d1SDavid du Colombier 	 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
1093e12c5d1SDavid du Colombier 	 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,}
1103e12c5d1SDavid du Colombier };
1113e12c5d1SDavid du Colombier 
1127dd7cddfSDavid du Colombier Cursor pixel = {
1137dd7cddfSDavid du Colombier 	{-7, -7},
1147dd7cddfSDavid du Colombier 	{0x1f, 0xf8, 0x3f, 0xfc,  0x7f, 0xfe,  0xf8, 0x1f,
1157dd7cddfSDavid du Colombier 	0xf0, 0x0f,  0xe0, 0x07, 0xe0, 0x07, 0xfe, 0x7f,
1167dd7cddfSDavid du Colombier 	0xfe, 0x7f, 0xe0, 0x07, 0xe0, 0x07, 0xf0, 0x0f,
1177dd7cddfSDavid du Colombier 	0x78, 0x1f, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0xf8, },
1187dd7cddfSDavid du Colombier 	{0x00, 0x00, 0x0f, 0xf0, 0x31, 0x8c, 0x21, 0x84,
1197dd7cddfSDavid du Colombier 	0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x40, 0x02,
1207dd7cddfSDavid du Colombier 	0x40, 0x02, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
1217dd7cddfSDavid du Colombier 	0x21, 0x84, 0x31, 0x8c, 0x0f, 0xf0, 0x00, 0x00, }
1227dd7cddfSDavid du Colombier };
1237dd7cddfSDavid du Colombier 
1243e12c5d1SDavid du Colombier Cursor busy = {
1253e12c5d1SDavid du Colombier 	{-7, -7},
1263e12c5d1SDavid du Colombier 	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1273e12c5d1SDavid du Colombier 	 0x00, 0x00, 0x00, 0x0c, 0x00, 0x8e, 0x1d, 0xc7,
1283e12c5d1SDavid du Colombier 	 0xff, 0xe3, 0xff, 0xf3, 0xff, 0xff, 0x7f, 0xfe,
1293e12c5d1SDavid du Colombier 	 0x3f, 0xf8, 0x17, 0xf0, 0x03, 0xe0, 0x00, 0x00,},
1303e12c5d1SDavid du Colombier 	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1313e12c5d1SDavid du Colombier 	 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x82,
1323e12c5d1SDavid du Colombier 	 0x04, 0x41, 0xff, 0xe1, 0x5f, 0xf1, 0x3f, 0xfe,
1333e12c5d1SDavid du Colombier 	 0x17, 0xf0, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00,}
1343e12c5d1SDavid du Colombier };
1353e12c5d1SDavid du Colombier 
1363e12c5d1SDavid du Colombier Cursor skull = {
1373e12c5d1SDavid du Colombier 	{-7,-7},
1383e12c5d1SDavid du Colombier 	{0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xe7, 0xe7,
1393e12c5d1SDavid du Colombier 	 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfc, 0x1f, 0xf8,
1403e12c5d1SDavid du Colombier 	 0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff,
1413e12c5d1SDavid du Colombier 	 0xef, 0xf7, 0xc7, 0xe3, 0x00, 0x00, 0x00, 0x00,},
1423e12c5d1SDavid du Colombier 	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
1433e12c5d1SDavid du Colombier 	 0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
1443e12c5d1SDavid du Colombier 	 0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
1453e12c5d1SDavid du Colombier 	 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
1463e12c5d1SDavid du Colombier };
1473e12c5d1SDavid du Colombier 
1483e12c5d1SDavid du Colombier Rectangle	cntlr;		/* control region */
1493e12c5d1SDavid du Colombier Rectangle	editr;		/* editing region */
1503e12c5d1SDavid du Colombier Rectangle	textr;		/* text region */
1513e12c5d1SDavid du Colombier Thing		*thing;
1523e12c5d1SDavid du Colombier Mouse		mouse;
1533e12c5d1SDavid du Colombier char		hex[] = "0123456789abcdefABCDEF";
1543e12c5d1SDavid du Colombier jmp_buf		err;
1553e12c5d1SDavid du Colombier char		*file;
1563e12c5d1SDavid du Colombier int		mag;
1577dd7cddfSDavid du Colombier int		but1val = 0;
1587dd7cddfSDavid du Colombier int		but2val = 255;
1597dd7cddfSDavid du Colombier int		invert = 0;
1607dd7cddfSDavid du Colombier Image		*values[256];
1617dd7cddfSDavid du Colombier Image		*greyvalues[256];
1623e12c5d1SDavid du Colombier uchar		data[8192];
1633e12c5d1SDavid du Colombier 
1643e12c5d1SDavid du Colombier Thing*	tget(char*);
1653e12c5d1SDavid du Colombier void	mesg(char*, ...);
1667dd7cddfSDavid du Colombier void	drawthing(Thing*, int);
1673e12c5d1SDavid du Colombier void	select(void);
1683e12c5d1SDavid du Colombier void	menu(void);
1697dd7cddfSDavid du Colombier void	error(Display*, char*);
1703e12c5d1SDavid du Colombier void	buttons(int);
1713e12c5d1SDavid du Colombier void	drawall(void);
1723e12c5d1SDavid du Colombier void	tclose1(Thing*);
1733e12c5d1SDavid du Colombier 
1743e12c5d1SDavid du Colombier void
main(int argc,char * argv[])1753e12c5d1SDavid du Colombier main(int argc, char *argv[])
1763e12c5d1SDavid du Colombier {
1777dd7cddfSDavid du Colombier 	int i;
1783e12c5d1SDavid du Colombier 	Event e;
1793e12c5d1SDavid du Colombier 	Thing *t;
1803e12c5d1SDavid du Colombier 
1813e12c5d1SDavid du Colombier 	mag = Mag;
1827dd7cddfSDavid du Colombier 	if(initdraw(error, 0, "tweak") < 0){
1837dd7cddfSDavid du Colombier 		fprint(2, "tweak: initdraw failed: %r\n");
1847dd7cddfSDavid du Colombier 		exits("initdraw");
1857dd7cddfSDavid du Colombier 	}
1867dd7cddfSDavid du Colombier 	for(i=0; i<256; i++){
1877dd7cddfSDavid du Colombier 		values[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, cmap2rgba(i));
1887dd7cddfSDavid du Colombier 		greyvalues[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, (i<<24)|(i<<16)|(i<<8)|0xFF);
1897dd7cddfSDavid du Colombier 		if(values[i] == 0 || greyvalues[i] == 0)
1907dd7cddfSDavid du Colombier 			drawerror(display, "can't allocate image");
1917dd7cddfSDavid du Colombier 	}
1923e12c5d1SDavid du Colombier 	einit(Emouse|Ekeyboard);
1937dd7cddfSDavid du Colombier 	eresized(0);
1943e12c5d1SDavid du Colombier 	i = 1;
1953e12c5d1SDavid du Colombier 	setjmp(err);
1963e12c5d1SDavid du Colombier 	for(; i<argc; i++){
1973e12c5d1SDavid du Colombier 		file = argv[i];
1983e12c5d1SDavid du Colombier 		t = tget(argv[i]);
1993e12c5d1SDavid du Colombier 		if(t)
2007dd7cddfSDavid du Colombier 			drawthing(t, 1);
2017dd7cddfSDavid du Colombier 		flushimage(display, 1);
2023e12c5d1SDavid du Colombier 	}
2033e12c5d1SDavid du Colombier 	file = 0;
2043e12c5d1SDavid du Colombier 	setjmp(err);
2053e12c5d1SDavid du Colombier 	for(;;)
2063e12c5d1SDavid du Colombier 		switch(event(&e)){
2073e12c5d1SDavid du Colombier 		case Ekeyboard:
2083e12c5d1SDavid du Colombier 			break;
2093e12c5d1SDavid du Colombier 		case Emouse:
2103e12c5d1SDavid du Colombier 			mouse = e.mouse;
2113e12c5d1SDavid du Colombier 			if(mouse.buttons & 3){
2123e12c5d1SDavid du Colombier 				select();
2133e12c5d1SDavid du Colombier 				break;
2143e12c5d1SDavid du Colombier 			}
2153e12c5d1SDavid du Colombier 			if(mouse.buttons & 4)
2163e12c5d1SDavid du Colombier 				menu();
2173e12c5d1SDavid du Colombier 		}
2183e12c5d1SDavid du Colombier }
2193e12c5d1SDavid du Colombier 
2203e12c5d1SDavid du Colombier void
error(Display *,char * s)2217dd7cddfSDavid du Colombier error(Display*, char *s)
2223e12c5d1SDavid du Colombier {
2233e12c5d1SDavid du Colombier 	if(file)
2243e12c5d1SDavid du Colombier 		mesg("can't read %s: %s: %r", file, s);
2253e12c5d1SDavid du Colombier 	else
2263e12c5d1SDavid du Colombier 		mesg("/dev/bitblt error: %s", s);
2273e12c5d1SDavid du Colombier 	if(err[0])
2283e12c5d1SDavid du Colombier 		longjmp(err, 1);
2293e12c5d1SDavid du Colombier 	exits(s);
2303e12c5d1SDavid du Colombier }
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier void
redraw(Thing * t)2333e12c5d1SDavid du Colombier redraw(Thing *t)
2343e12c5d1SDavid du Colombier {
2353e12c5d1SDavid du Colombier 	Thing *nt;
2363e12c5d1SDavid du Colombier 	Point p;
2373e12c5d1SDavid du Colombier 
2383e12c5d1SDavid du Colombier 	if(thing==0 || thing==t)
2397dd7cddfSDavid du Colombier 		draw(screen, editr, display->white, nil, ZP);
2403e12c5d1SDavid du Colombier 	if(thing == 0)
2413e12c5d1SDavid du Colombier 		return;
2423e12c5d1SDavid du Colombier 	if(thing != t){
2433e12c5d1SDavid du Colombier 		for(nt=thing; nt->next!=t; nt=nt->next)
2443e12c5d1SDavid du Colombier 			;
2457dd7cddfSDavid du Colombier 		draw(screen, Rect(screen->r.min.x, nt->er.max.y, editr.max.x, editr.max.y),
2467dd7cddfSDavid du Colombier 			display->white, nil, ZP);
2473e12c5d1SDavid du Colombier 	}
2483e12c5d1SDavid du Colombier 	for(nt=t; nt; nt=nt->next){
2497dd7cddfSDavid du Colombier 		drawthing(nt, 0);
2503e12c5d1SDavid du Colombier 		if(nt->next == 0){
2513e12c5d1SDavid du Colombier 			p = Pt(editr.min.x, nt->er.max.y);
2527dd7cddfSDavid du Colombier 			draw(screen, Rpt(p, editr.max), display->white, nil, ZP);
2533e12c5d1SDavid du Colombier 		}
2543e12c5d1SDavid du Colombier 	}
2553e12c5d1SDavid du Colombier 	mesg("");
2563e12c5d1SDavid du Colombier }
2573e12c5d1SDavid du Colombier 
2583e12c5d1SDavid du Colombier void
eresized(int new)2597dd7cddfSDavid du Colombier eresized(int new)
2603e12c5d1SDavid du Colombier {
2617dd7cddfSDavid du Colombier 	if(new && getwindow(display, Refnone) < 0)
2627dd7cddfSDavid du Colombier 		error(display, "can't reattach to window");
2637dd7cddfSDavid du Colombier 	cntlr = insetrect(screen->clipr, 1);
2643e12c5d1SDavid du Colombier 	editr = cntlr;
2653e12c5d1SDavid du Colombier 	textr = editr;
2663e12c5d1SDavid du Colombier 	textr.min.y = textr.max.y - font->height;
2673e12c5d1SDavid du Colombier 	cntlr.max.y = cntlr.min.y + font->height;
2683e12c5d1SDavid du Colombier 	editr.min.y = cntlr.max.y+1;
2693e12c5d1SDavid du Colombier 	editr.max.y = textr.min.y-1;
2707dd7cddfSDavid du Colombier 	draw(screen, screen->clipr, display->white, nil, ZP);
2717dd7cddfSDavid du Colombier 	draw(screen, Rect(editr.min.x, editr.max.y, editr.max.x+1, editr.max.y+1), display->black, nil, ZP);
2727dd7cddfSDavid du Colombier 	replclipr(screen, 0, editr);
2733e12c5d1SDavid du Colombier 	drawall();
2743e12c5d1SDavid du Colombier }
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier void
mesgstr(Point p,int line,char * s)2773e12c5d1SDavid du Colombier mesgstr(Point p, int line, char *s)
2783e12c5d1SDavid du Colombier {
2793e12c5d1SDavid du Colombier 	Rectangle c, r;
2803e12c5d1SDavid du Colombier 
2813e12c5d1SDavid du Colombier 	r.min = p;
2823e12c5d1SDavid du Colombier 	r.min.y += line*font->height;
2833e12c5d1SDavid du Colombier 	r.max.y = r.min.y+font->height;
2843e12c5d1SDavid du Colombier 	r.max.x = editr.max.x;
2857dd7cddfSDavid du Colombier 	c = screen->clipr;
2867dd7cddfSDavid du Colombier 	replclipr(screen, 0, r);
2877dd7cddfSDavid du Colombier 	draw(screen, r, values[0xDD], nil, ZP);
2883e12c5d1SDavid du Colombier 	r.min.x++;
2897dd7cddfSDavid du Colombier 	string(screen, r.min, display->black, ZP, font, s);
2907dd7cddfSDavid du Colombier 	replclipr(screen, 0, c);
2917dd7cddfSDavid du Colombier 	flushimage(display, 1);
2923e12c5d1SDavid du Colombier }
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier void
mesg(char * fmt,...)2953e12c5d1SDavid du Colombier mesg(char *fmt, ...)
2963e12c5d1SDavid du Colombier {
2973e12c5d1SDavid du Colombier 	char buf[1024];
2987dd7cddfSDavid du Colombier 	va_list arg;
2993e12c5d1SDavid du Colombier 
3007dd7cddfSDavid du Colombier 	va_start(arg, fmt);
3019a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, arg);
3027dd7cddfSDavid du Colombier 	va_end(arg);
3033e12c5d1SDavid du Colombier 	mesgstr(textr.min, 0, buf);
3043e12c5d1SDavid du Colombier }
3053e12c5d1SDavid du Colombier 
3063e12c5d1SDavid du Colombier void
tmesg(Thing * t,int line,char * fmt,...)3073e12c5d1SDavid du Colombier tmesg(Thing *t, int line, char *fmt, ...)
3083e12c5d1SDavid du Colombier {
3093e12c5d1SDavid du Colombier 	char buf[1024];
3107dd7cddfSDavid du Colombier 	va_list arg;
3113e12c5d1SDavid du Colombier 
3127dd7cddfSDavid du Colombier 	va_start(arg, fmt);
3139a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, arg);
3147dd7cddfSDavid du Colombier 	va_end(arg);
3153e12c5d1SDavid du Colombier 	mesgstr(t->tr.min, line, buf);
3163e12c5d1SDavid du Colombier }
3173e12c5d1SDavid du Colombier 
3183e12c5d1SDavid du Colombier 
3193e12c5d1SDavid du Colombier void
scntl(char * l)3203e12c5d1SDavid du Colombier scntl(char *l)
3213e12c5d1SDavid du Colombier {
3227dd7cddfSDavid du Colombier 	sprint(l, "mag: %d  but1: %d  but2: %d  invert-on-copy: %c", mag, but1val, but2val, "ny"[invert]);
3233e12c5d1SDavid du Colombier }
3243e12c5d1SDavid du Colombier 
3253e12c5d1SDavid du Colombier void
cntl(void)3263e12c5d1SDavid du Colombier cntl(void)
3273e12c5d1SDavid du Colombier {
3283e12c5d1SDavid du Colombier 	char buf[256];
3293e12c5d1SDavid du Colombier 
3303e12c5d1SDavid du Colombier 	scntl(buf);
3313e12c5d1SDavid du Colombier 	mesgstr(cntlr.min, 0, buf);
3323e12c5d1SDavid du Colombier }
3333e12c5d1SDavid du Colombier 
3343e12c5d1SDavid du Colombier void
stext(Thing * t,char * l0,char * l1)3353e12c5d1SDavid du Colombier stext(Thing *t, char *l0, char *l1)
3363e12c5d1SDavid du Colombier {
3373e12c5d1SDavid du Colombier 	Fontchar *fc;
3383e12c5d1SDavid du Colombier 	char buf[256];
3393e12c5d1SDavid du Colombier 
3403e12c5d1SDavid du Colombier 	l1[0] = 0;
3417dd7cddfSDavid du Colombier 	sprint(buf, "depth:%d r:%d %d  %d %d ",
3427dd7cddfSDavid du Colombier 		t->b->depth, t->b->r.min.x, t->b->r.min.y,
3433e12c5d1SDavid du Colombier 		t->b->r.max.x, t->b->r.max.y);
3443e12c5d1SDavid du Colombier 	if(t->parent)
3453e12c5d1SDavid du Colombier 		sprint(buf+strlen(buf), "mag: %d ", t->mag);
3463e12c5d1SDavid du Colombier 	sprint(l0, "%s file: %s", buf, t->name);
3473e12c5d1SDavid du Colombier 	if(t->c >= 0){
3483e12c5d1SDavid du Colombier 		fc = &t->parent->s->info[t->c];
3493e12c5d1SDavid du Colombier 		sprint(l1, "c(hex): %x c(char): %C x: %d "
3503e12c5d1SDavid du Colombier 			   "top: %d bottom: %d left: %d width: %d iwidth: %d",
3517dd7cddfSDavid du Colombier 			(int)(t->c+t->parent->off), (int)(t->c+t->parent->off),
3523e12c5d1SDavid du Colombier 			fc->x, fc->top, fc->bottom, fc->left,
3533e12c5d1SDavid du Colombier 			fc->width, Dx(t->b->r));
3543e12c5d1SDavid du Colombier 	}else if(t->s)
3553e12c5d1SDavid du Colombier 		sprint(l1, "offset(hex): %ux n:%d  height:%d  ascent:%d",
3563e12c5d1SDavid du Colombier 			t->off, t->s->n, t->s->height, t->s->ascent);
3573e12c5d1SDavid du Colombier }
3583e12c5d1SDavid du Colombier 
3593e12c5d1SDavid du Colombier void
text(Thing * t)3603e12c5d1SDavid du Colombier text(Thing *t)
3613e12c5d1SDavid du Colombier {
3623e12c5d1SDavid du Colombier 	char l0[256], l1[256];
3633e12c5d1SDavid du Colombier 
3643e12c5d1SDavid du Colombier 	stext(t, l0, l1);
3653e12c5d1SDavid du Colombier 	tmesg(t, 0, l0);
3663e12c5d1SDavid du Colombier 	if(l1[0])
3673e12c5d1SDavid du Colombier 		tmesg(t, 1, l1);
3683e12c5d1SDavid du Colombier }
3693e12c5d1SDavid du Colombier 
3703e12c5d1SDavid du Colombier void
drawall(void)3713e12c5d1SDavid du Colombier drawall(void)
3723e12c5d1SDavid du Colombier {
3733e12c5d1SDavid du Colombier 	Thing *t;
3743e12c5d1SDavid du Colombier 
3753e12c5d1SDavid du Colombier 	cntl();
3763e12c5d1SDavid du Colombier 	for(t=thing; t; t=t->next)
3777dd7cddfSDavid du Colombier 		drawthing(t, 0);
3783e12c5d1SDavid du Colombier }
3793e12c5d1SDavid du Colombier 
380*bacfa46cSDavid du Colombier /* imported from libdraw/arith.c to permit an extern log2 function */
381*bacfa46cSDavid du Colombier static int log2[] = {
382*bacfa46cSDavid du Colombier 	-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
383*bacfa46cSDavid du Colombier 	-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
384*bacfa46cSDavid du Colombier };
385*bacfa46cSDavid du Colombier 
3863e12c5d1SDavid du Colombier int
value(Image * b,int x)3877dd7cddfSDavid du Colombier value(Image *b, int x)
3883e12c5d1SDavid du Colombier {
3893e12c5d1SDavid du Colombier 	int v, l, w;
3903e12c5d1SDavid du Colombier 	uchar mask;
3913e12c5d1SDavid du Colombier 
3927dd7cddfSDavid du Colombier 	w = b->depth;
3937dd7cddfSDavid du Colombier 	if(w > 8){
3943e12c5d1SDavid du Colombier 		mesg("ldepth too large");
3953e12c5d1SDavid du Colombier 		return 0;
3963e12c5d1SDavid du Colombier 	}
3977dd7cddfSDavid du Colombier 	l = log2[w];
3987dd7cddfSDavid du Colombier 	mask = (1<<w)-1;		/* ones at right end of word */
3993e12c5d1SDavid du Colombier 	x -= b->r.min.x&~(7>>l);	/* adjust x relative to first pixel */
4003e12c5d1SDavid du Colombier 	v = data[x>>(3-l)];
4013e12c5d1SDavid du Colombier 	v >>= ((7>>l)<<l) - ((x&(7>>l))<<l);	/* pixel at right end of word */
4023e12c5d1SDavid du Colombier 	v &= mask;			/* pixel at right end of word */
4033e12c5d1SDavid du Colombier 	return v;
4043e12c5d1SDavid du Colombier }
4053e12c5d1SDavid du Colombier 
4063e12c5d1SDavid du Colombier int
bvalue(int v,int d)4077dd7cddfSDavid du Colombier bvalue(int v, int d)
4083e12c5d1SDavid du Colombier {
4097dd7cddfSDavid du Colombier 	v &= (1<<d)-1;
4107dd7cddfSDavid du Colombier 	if(d > screen->depth)
4117dd7cddfSDavid du Colombier 		v >>= d - screen->depth;
412219b2ee8SDavid du Colombier 	else
4137dd7cddfSDavid du Colombier 		while(d < screen->depth && d < 8){
4147dd7cddfSDavid du Colombier 			v |= v << d;
4157dd7cddfSDavid du Colombier 			d <<= 1;
4163e12c5d1SDavid du Colombier 		}
4177dd7cddfSDavid du Colombier 	if(v<0 || v>255){
4187dd7cddfSDavid du Colombier 		mesg("internal error: bad color");
4197dd7cddfSDavid du Colombier 		return Blue;
4207dd7cddfSDavid du Colombier 	}
4217dd7cddfSDavid du Colombier 	return v;
4223e12c5d1SDavid du Colombier }
4233e12c5d1SDavid du Colombier 
4243e12c5d1SDavid du Colombier void
drawthing(Thing * nt,int link)4257dd7cddfSDavid du Colombier drawthing(Thing *nt, int link)
4263e12c5d1SDavid du Colombier {
4273e12c5d1SDavid du Colombier 	int nl, nf, i, x, y, sx, sy, fdx, dx, dy, v;
4283e12c5d1SDavid du Colombier 	Thing *t;
4293e12c5d1SDavid du Colombier 	Subfont *s;
4307dd7cddfSDavid du Colombier 	Image *b, *col;
4313e12c5d1SDavid du Colombier 	Point p, p1, p2;
4323e12c5d1SDavid du Colombier 
4333e12c5d1SDavid du Colombier 	if(link){
4343e12c5d1SDavid du Colombier 		nt->next = 0;
4353e12c5d1SDavid du Colombier 		if(thing == 0){
4363e12c5d1SDavid du Colombier 			thing = nt;
4373e12c5d1SDavid du Colombier 			y = editr.min.y;
4383e12c5d1SDavid du Colombier 		}else{
4393e12c5d1SDavid du Colombier 			for(t=thing; t->next; t=t->next)
4403e12c5d1SDavid du Colombier 				;
4413e12c5d1SDavid du Colombier 			t->next = nt;
4423e12c5d1SDavid du Colombier 			y = t->er.max.y;
4433e12c5d1SDavid du Colombier 		}
4443e12c5d1SDavid du Colombier 	}else{
4453e12c5d1SDavid du Colombier 		if(thing == nt)
4463e12c5d1SDavid du Colombier 			y = editr.min.y;
4473e12c5d1SDavid du Colombier 		else{
4483e12c5d1SDavid du Colombier 			for(t=thing; t->next!=nt; t=t->next)
4493e12c5d1SDavid du Colombier 				;
4503e12c5d1SDavid du Colombier 			y = t->er.max.y;
4513e12c5d1SDavid du Colombier 		}
4523e12c5d1SDavid du Colombier 	}
4533e12c5d1SDavid du Colombier 	s = nt->s;
4543e12c5d1SDavid du Colombier 	b = nt->b;
4553e12c5d1SDavid du Colombier 	nl = font->height;
4563e12c5d1SDavid du Colombier 	if(s || nt->c>=0)
4573e12c5d1SDavid du Colombier 		nl += font->height;
4583e12c5d1SDavid du Colombier 	fdx = Dx(editr) - 2*Border;
4593e12c5d1SDavid du Colombier 	dx = Dx(b->r);
4603e12c5d1SDavid du Colombier 	dy = Dy(b->r);
4613e12c5d1SDavid du Colombier 	if(nt->mag > 1){
4623e12c5d1SDavid du Colombier 		dx *= nt->mag;
4633e12c5d1SDavid du Colombier 		dy *= nt->mag;
4643e12c5d1SDavid du Colombier 		fdx -= fdx%nt->mag;
4653e12c5d1SDavid du Colombier 	}
4663e12c5d1SDavid du Colombier 	nf = 1 + dx/fdx;
4673e12c5d1SDavid du Colombier 	nt->er.min.y = y;
4683e12c5d1SDavid du Colombier 	nt->er.min.x = editr.min.x;
4693e12c5d1SDavid du Colombier 	nt->er.max.x = nt->er.min.x + Border + dx + Border;
4703e12c5d1SDavid du Colombier 	if(nt->er.max.x > editr.max.x)
4713e12c5d1SDavid du Colombier 		nt->er.max.x = editr.max.x;
4723e12c5d1SDavid du Colombier 	nt->er.max.y = nt->er.min.y + Border + nf*(dy+Border);
4737dd7cddfSDavid du Colombier 	nt->r = insetrect(nt->er, Border);
4743e12c5d1SDavid du Colombier 	nt->er.max.x = editr.max.x;
4757dd7cddfSDavid du Colombier 	draw(screen, nt->er, display->white, nil, ZP);
4763e12c5d1SDavid du Colombier 	for(i=0; i<nf; i++){
4773e12c5d1SDavid du Colombier 		p1 = Pt(nt->r.min.x-1, nt->r.min.y+i*(Border+dy));
4783e12c5d1SDavid du Colombier 		/* draw portion of bitmap */
4793e12c5d1SDavid du Colombier 		p = Pt(p1.x+1, p1.y);
4803e12c5d1SDavid du Colombier 		if(nt->mag == 1)
4817dd7cddfSDavid du Colombier 			draw(screen, Rect(p.x, p.y, p.x+fdx+Dx(b->r), p.y+Dy(b->r)),
4827dd7cddfSDavid du Colombier 				b, nil, Pt(b->r.min.x+i*fdx, b->r.min.y));
4833e12c5d1SDavid du Colombier 		else{
4843e12c5d1SDavid du Colombier 			for(y=b->r.min.y; y<b->r.max.y; y++){
4853e12c5d1SDavid du Colombier 				sy = p.y+(y-b->r.min.y)*nt->mag;
4867dd7cddfSDavid du Colombier 				unloadimage(b, Rect(b->r.min.x, y, b->r.max.x, y+1), data, sizeof data);
4873e12c5d1SDavid du Colombier 				for(x=b->r.min.x+i*(fdx/nt->mag); x<b->r.max.x; x++){
4883e12c5d1SDavid du Colombier 					sx = p.x+(x-i*(fdx/nt->mag)-b->r.min.x)*nt->mag;
4893e12c5d1SDavid du Colombier 					if(sx >= nt->r.max.x)
4903e12c5d1SDavid du Colombier 						break;
4917dd7cddfSDavid du Colombier 					v = bvalue(value(b, x), b->depth);
4927dd7cddfSDavid du Colombier 					if(v == 255)
4937dd7cddfSDavid du Colombier 						continue;
4947dd7cddfSDavid du Colombier 					if(b->chan == GREY8)
4957dd7cddfSDavid du Colombier 						draw(screen, Rect(sx, sy, sx+nt->mag, sy+nt->mag),
4967dd7cddfSDavid du Colombier 							greyvalues[v], nil, ZP);
4977dd7cddfSDavid du Colombier 					else
4987dd7cddfSDavid du Colombier 						draw(screen, Rect(sx, sy, sx+nt->mag, sy+nt->mag),
4997dd7cddfSDavid du Colombier 							values[v], nil, ZP);
5003e12c5d1SDavid du Colombier 				}
5013e12c5d1SDavid du Colombier 
5023e12c5d1SDavid du Colombier 			}
5033e12c5d1SDavid du Colombier 		}
5043e12c5d1SDavid du Colombier 		/* line down left */
5057dd7cddfSDavid du Colombier 		if(i == 0)
5067dd7cddfSDavid du Colombier 			col = display->black;
5073e12c5d1SDavid du Colombier 		else
5087dd7cddfSDavid du Colombier 			col = display->white;
5097dd7cddfSDavid du Colombier 		draw(screen, Rect(p1.x, p1.y, p1.x+1, p1.y+dy+Border), col, nil, ZP);
5107dd7cddfSDavid du Colombier 		/* line across top */
5117dd7cddfSDavid du Colombier 		draw(screen, Rect(p1.x, p1.y-1, nt->r.max.x+Border, p1.y), display->black, nil, ZP);
5127dd7cddfSDavid du Colombier 		p2 = p1;
5137dd7cddfSDavid du Colombier 		if(i == nf-1){
5147dd7cddfSDavid du Colombier 			p2.x += 1 + dx%fdx;
5157dd7cddfSDavid du Colombier 			col = display->black;
5167dd7cddfSDavid du Colombier 		}else{
5173e12c5d1SDavid du Colombier 			p2.x = nt->r.max.x;
5187dd7cddfSDavid du Colombier 			col = display->white;
5197dd7cddfSDavid du Colombier 		}
5203e12c5d1SDavid du Colombier 		/* line down right */
5217dd7cddfSDavid du Colombier 		draw(screen, Rect(p2.x, p2.y, p2.x+1, p2.y+dy+Border), col, nil, ZP);
5223e12c5d1SDavid du Colombier 		/* line across bottom */
5233e12c5d1SDavid du Colombier 		if(i == nf-1){
5243e12c5d1SDavid du Colombier 			p1.y += Border+dy;
5257dd7cddfSDavid du Colombier 			draw(screen, Rect(p1.x, p1.y-1, p2.x,p1.y), display->black, nil, ZP);
5263e12c5d1SDavid du Colombier 		}
5273e12c5d1SDavid du Colombier 	}
5283e12c5d1SDavid du Colombier 	nt->tr.min.x = editr.min.x;
5293e12c5d1SDavid du Colombier 	nt->tr.max.x = editr.max.x;
5303e12c5d1SDavid du Colombier 	nt->tr.min.y = nt->er.max.y + Border;
5313e12c5d1SDavid du Colombier 	nt->tr.max.y = nt->tr.min.y + nl;
5323e12c5d1SDavid du Colombier 	nt->er.max.y = nt->tr.max.y + Border;
5333e12c5d1SDavid du Colombier 	text(nt);
5343e12c5d1SDavid du Colombier }
5353e12c5d1SDavid du Colombier 
5363e12c5d1SDavid du Colombier int
tohex(int c)5373e12c5d1SDavid du Colombier tohex(int c)
5383e12c5d1SDavid du Colombier {
5393e12c5d1SDavid du Colombier 	if('0'<=c && c<='9')
5403e12c5d1SDavid du Colombier 		return c - '0';
5413e12c5d1SDavid du Colombier 	if('a'<=c && c<='f')
5423e12c5d1SDavid du Colombier 		return 10 + (c - 'a');
5433e12c5d1SDavid du Colombier 	if('A'<=c && c<='F')
5443e12c5d1SDavid du Colombier 		return 10 + (c - 'A');
54543f733d7SDavid du Colombier 	return 0;
5463e12c5d1SDavid du Colombier }
5473e12c5d1SDavid du Colombier 
5483e12c5d1SDavid du Colombier Thing*
tget(char * file)5493e12c5d1SDavid du Colombier tget(char *file)
5503e12c5d1SDavid du Colombier {
5517dd7cddfSDavid du Colombier 	int i, j, fd, face, x, y, c, chan;
5527dd7cddfSDavid du Colombier 	Image *b;
5533e12c5d1SDavid du Colombier 	Subfont *s;
5543e12c5d1SDavid du Colombier 	Thing *t;
5559a747e4fSDavid du Colombier 	Dir *d;
5563e12c5d1SDavid du Colombier 	jmp_buf oerr;
5573e12c5d1SDavid du Colombier 	uchar buf[256];
5583e12c5d1SDavid du Colombier 	char *data;
5593e12c5d1SDavid du Colombier 
5609a747e4fSDavid du Colombier 	buf[0] = '\0';
5619a747e4fSDavid du Colombier 	errstr((char*)buf, sizeof buf);	/* flush pending error message */
5623e12c5d1SDavid du Colombier 	memmove(oerr, err, sizeof err);
5639a747e4fSDavid du Colombier 	d = nil;
5643e12c5d1SDavid du Colombier 	if(setjmp(err)){
5653e12c5d1SDavid du Colombier    Err:
5669a747e4fSDavid du Colombier 		free(d);
5673e12c5d1SDavid du Colombier 		memmove(err, oerr, sizeof err);
5683e12c5d1SDavid du Colombier 		return 0;
5693e12c5d1SDavid du Colombier 	}
5703e12c5d1SDavid du Colombier 	fd = open(file, OREAD);
5713e12c5d1SDavid du Colombier 	if(fd < 0){
5723e12c5d1SDavid du Colombier 		mesg("can't open %s: %r", file);
5733e12c5d1SDavid du Colombier 		goto Err;
5743e12c5d1SDavid du Colombier 	}
5759a747e4fSDavid du Colombier 	d = dirfstat(fd);
5769a747e4fSDavid du Colombier 	if(d == nil){
5773e12c5d1SDavid du Colombier 		mesg("can't stat bitmap file %s: %r", file);
5783e12c5d1SDavid du Colombier 		close(fd);
5793e12c5d1SDavid du Colombier 		goto Err;
5803e12c5d1SDavid du Colombier 	}
5817dd7cddfSDavid du Colombier 	if(read(fd, buf, 11) != 11){
5823e12c5d1SDavid du Colombier 		mesg("can't read %s: %r", file);
5833e12c5d1SDavid du Colombier 		close(fd);
5843e12c5d1SDavid du Colombier 		goto Err;
5853e12c5d1SDavid du Colombier 	}
5863e12c5d1SDavid du Colombier 	seek(fd, 0, 0);
5877dd7cddfSDavid du Colombier 	data = (char*)buf;
5887dd7cddfSDavid du Colombier 	if(*data == '{')
5897dd7cddfSDavid du Colombier 		data++;
5907dd7cddfSDavid du Colombier 	if(memcmp(data, "0x", 2)==0 && data[4]==','){
5917dd7cddfSDavid du Colombier 		/*
5927dd7cddfSDavid du Colombier 		 * cursor file
5937dd7cddfSDavid du Colombier 		 */
5947dd7cddfSDavid du Colombier 		face = CURSOR;
5957dd7cddfSDavid du Colombier 		s = 0;
5969a747e4fSDavid du Colombier 		data = malloc(d->length+1);
5977dd7cddfSDavid du Colombier 		if(data == 0){
5987dd7cddfSDavid du Colombier 			mesg("can't malloc buffer: %r");
5997dd7cddfSDavid du Colombier 			close(fd);
6007dd7cddfSDavid du Colombier 			goto Err;
6017dd7cddfSDavid du Colombier 		}
6029a747e4fSDavid du Colombier 		data[d->length] = 0;
6039a747e4fSDavid du Colombier 		if(read(fd, data, d->length) != d->length){
6047dd7cddfSDavid du Colombier 			mesg("can't read cursor file %s: %r", file);
6057dd7cddfSDavid du Colombier 			close(fd);
6067dd7cddfSDavid du Colombier 			goto Err;
6077dd7cddfSDavid du Colombier 		}
6087dd7cddfSDavid du Colombier 		b = allocimage(display, Rect(0, 0, 16, 32), GREY1, 0, DNofill);
6097dd7cddfSDavid du Colombier 		if(b == 0){
6107dd7cddfSDavid du Colombier 			mesg("image alloc failed file %s: %r", file);
6117dd7cddfSDavid du Colombier 			free(data);
6127dd7cddfSDavid du Colombier 			close(fd);
6137dd7cddfSDavid du Colombier 			goto Err;
6147dd7cddfSDavid du Colombier 		}
6157dd7cddfSDavid du Colombier 		i = 0;
6167dd7cddfSDavid du Colombier 		for(x=0;x<64; ){
6177dd7cddfSDavid du Colombier 			if((c=data[i]) == '\0')
6187dd7cddfSDavid du Colombier 				goto ill;
6197dd7cddfSDavid du Colombier 			if(c=='0' && data[i+1] == 'x'){
6207dd7cddfSDavid du Colombier 				i += 2;
6217dd7cddfSDavid du Colombier 				continue;
6227dd7cddfSDavid du Colombier 			}
6237dd7cddfSDavid du Colombier 			if(strchr(hex, c)){
6247dd7cddfSDavid du Colombier 				buf[x++] = (tohex(c)<<4) | tohex(data[i+1]);
6257dd7cddfSDavid du Colombier 				i += 2;
6267dd7cddfSDavid du Colombier 				continue;
6277dd7cddfSDavid du Colombier 			}
6287dd7cddfSDavid du Colombier 			i++;
6297dd7cddfSDavid du Colombier 		}
6307dd7cddfSDavid du Colombier 		loadimage(b, Rect(0, 0, 16, 32), buf, sizeof buf);
6317dd7cddfSDavid du Colombier 		free(data);
6327dd7cddfSDavid du Colombier 	}else if(memcmp(buf, "0x", 2)==0){
6333e12c5d1SDavid du Colombier 		/*
6343e12c5d1SDavid du Colombier 		 * face file
6353e12c5d1SDavid du Colombier 		 */
6367dd7cddfSDavid du Colombier 		face = FACE;
6373e12c5d1SDavid du Colombier 		s = 0;
6389a747e4fSDavid du Colombier 		data = malloc(d->length+1);
6393e12c5d1SDavid du Colombier 		if(data == 0){
6403e12c5d1SDavid du Colombier 			mesg("can't malloc buffer: %r");
6413e12c5d1SDavid du Colombier 			close(fd);
6423e12c5d1SDavid du Colombier 			goto Err;
6433e12c5d1SDavid du Colombier 		}
6449a747e4fSDavid du Colombier 		data[d->length] = 0;
6459a747e4fSDavid du Colombier 		if(read(fd, data, d->length) != d->length){
6463e12c5d1SDavid du Colombier 			mesg("can't read bitmap file %s: %r", file);
6473e12c5d1SDavid du Colombier 			close(fd);
6483e12c5d1SDavid du Colombier 			goto Err;
6493e12c5d1SDavid du Colombier 		}
6509a747e4fSDavid du Colombier 		for(y=0,i=0; i<d->length; i++)
6513e12c5d1SDavid du Colombier 			if(data[i] == '\n')
6523e12c5d1SDavid du Colombier 				y++;
6533e12c5d1SDavid du Colombier 		if(y == 0){
6543e12c5d1SDavid du Colombier 	ill:
6553e12c5d1SDavid du Colombier 			mesg("ill-formed face file %s", file);
6563e12c5d1SDavid du Colombier 			close(fd);
6573e12c5d1SDavid du Colombier 			free(data);
6583e12c5d1SDavid du Colombier 			goto Err;
6593e12c5d1SDavid du Colombier 		}
6603e12c5d1SDavid du Colombier 		for(x=0,i=0; (c=data[i])!='\n'; ){
6613e12c5d1SDavid du Colombier 			if(c==',' || c==' ' || c=='\t'){
6623e12c5d1SDavid du Colombier 				i++;
6633e12c5d1SDavid du Colombier 				continue;
6643e12c5d1SDavid du Colombier 			}
6653e12c5d1SDavid du Colombier 			if(c=='0' && data[i+1] == 'x'){
6663e12c5d1SDavid du Colombier 				i += 2;
6673e12c5d1SDavid du Colombier 				continue;
6683e12c5d1SDavid du Colombier 			}
6693e12c5d1SDavid du Colombier 			if(strchr(hex, c)){
6703e12c5d1SDavid du Colombier 				x += 4;
6713e12c5d1SDavid du Colombier 				i++;
6723e12c5d1SDavid du Colombier 				continue;
6733e12c5d1SDavid du Colombier 			}
6743e12c5d1SDavid du Colombier 			goto ill;
6753e12c5d1SDavid du Colombier 		}
6763e12c5d1SDavid du Colombier 		if(x % y)
6773e12c5d1SDavid du Colombier 			goto ill;
6783e12c5d1SDavid du Colombier 		switch(x / y){
6793e12c5d1SDavid du Colombier 		default:
6803e12c5d1SDavid du Colombier 			goto ill;
6813e12c5d1SDavid du Colombier 		case 1:
6827dd7cddfSDavid du Colombier 			chan = GREY1;
6833e12c5d1SDavid du Colombier 			break;
6843e12c5d1SDavid du Colombier 		case 2:
6857dd7cddfSDavid du Colombier 			chan = GREY2;
6863e12c5d1SDavid du Colombier 			break;
6873e12c5d1SDavid du Colombier 		case 4:
6887dd7cddfSDavid du Colombier 			chan = GREY4;
6893e12c5d1SDavid du Colombier 			break;
6903e12c5d1SDavid du Colombier 		case 8:
6917dd7cddfSDavid du Colombier 			chan = CMAP8;
6923e12c5d1SDavid du Colombier 			break;
6933e12c5d1SDavid du Colombier 		}
6947dd7cddfSDavid du Colombier 		b = allocimage(display, Rect(0, 0, y, y), chan, 0, -1);
6953e12c5d1SDavid du Colombier 		if(b == 0){
6967dd7cddfSDavid du Colombier 			mesg("image alloc failed file %s: %r", file);
6973e12c5d1SDavid du Colombier 			free(data);
6983e12c5d1SDavid du Colombier 			close(fd);
6993e12c5d1SDavid du Colombier 			goto Err;
7003e12c5d1SDavid du Colombier 		}
7013e12c5d1SDavid du Colombier 		i = 0;
7023e12c5d1SDavid du Colombier 		for(j=0; j<y; j++){
7033e12c5d1SDavid du Colombier 			for(x=0; (c=data[i])!='\n'; ){
7043e12c5d1SDavid du Colombier 				if(c=='0' && data[i+1] == 'x'){
7053e12c5d1SDavid du Colombier 					i += 2;
7063e12c5d1SDavid du Colombier 					continue;
7073e12c5d1SDavid du Colombier 				}
7083e12c5d1SDavid du Colombier 				if(strchr(hex, c)){
7097dd7cddfSDavid du Colombier 					buf[x++] = ~((tohex(c)<<4) | tohex(data[i+1]));
7103e12c5d1SDavid du Colombier 					i += 2;
7113e12c5d1SDavid du Colombier 					continue;
7123e12c5d1SDavid du Colombier 				}
7137dd7cddfSDavid du Colombier 				i++;
7143e12c5d1SDavid du Colombier 			}
7153e12c5d1SDavid du Colombier 			i++;
7167dd7cddfSDavid du Colombier 			loadimage(b, Rect(0, j, y, j+1), buf, sizeof buf);
7173e12c5d1SDavid du Colombier 		}
7183e12c5d1SDavid du Colombier 		free(data);
7193e12c5d1SDavid du Colombier 	}else{
7207dd7cddfSDavid du Colombier 		face = NORMAL;
7213e12c5d1SDavid du Colombier 		s = 0;
7227dd7cddfSDavid du Colombier 		b = readimage(display, fd, 0);
7233e12c5d1SDavid du Colombier 		if(b == 0){
7243e12c5d1SDavid du Colombier 			mesg("can't read bitmap file %s: %r", file);
7253e12c5d1SDavid du Colombier 			close(fd);
7263e12c5d1SDavid du Colombier 			goto Err;
7273e12c5d1SDavid du Colombier 		}
7289a747e4fSDavid du Colombier 		if(seek(fd, 0, 1) < d->length)
7297dd7cddfSDavid du Colombier 			s = readsubfonti(display, file, fd, b, 0);
7303e12c5d1SDavid du Colombier 	}
7313e12c5d1SDavid du Colombier 	close(fd);
7323e12c5d1SDavid du Colombier 	t = malloc(sizeof(Thing));
7333e12c5d1SDavid du Colombier 	if(t == 0){
7343e12c5d1SDavid du Colombier    nomem:
7353e12c5d1SDavid du Colombier 		mesg("malloc failed: %r");
7363e12c5d1SDavid du Colombier 		if(s)
7377dd7cddfSDavid du Colombier 			freesubfont(s);
7387dd7cddfSDavid du Colombier 		else
7397dd7cddfSDavid du Colombier 			freeimage(b);
7403e12c5d1SDavid du Colombier 		goto Err;
7413e12c5d1SDavid du Colombier 	}
7423e12c5d1SDavid du Colombier 	t->name = strdup(file);
7433e12c5d1SDavid du Colombier 	if(t->name == 0){
7443e12c5d1SDavid du Colombier 		free(t);
7453e12c5d1SDavid du Colombier 		goto nomem;
7463e12c5d1SDavid du Colombier 	}
7473e12c5d1SDavid du Colombier 	t->b = b;
7483e12c5d1SDavid du Colombier 	t->s = s;
7493e12c5d1SDavid du Colombier 	t->face = face;
7503e12c5d1SDavid du Colombier 	t->mod = 0;
7513e12c5d1SDavid du Colombier 	t->parent = 0;
7523e12c5d1SDavid du Colombier 	t->c = -1;
7533e12c5d1SDavid du Colombier 	t->mag = 1;
7543e12c5d1SDavid du Colombier 	t->off = 0;
7553e12c5d1SDavid du Colombier 	memmove(err, oerr, sizeof err);
7563e12c5d1SDavid du Colombier 	return t;
7573e12c5d1SDavid du Colombier }
7583e12c5d1SDavid du Colombier 
7593e12c5d1SDavid du Colombier int
atline(int x,Point p,char * line,char * buf)7603e12c5d1SDavid du Colombier atline(int x, Point p, char *line, char *buf)
7613e12c5d1SDavid du Colombier {
7623e12c5d1SDavid du Colombier 	char *s, *c, *word, *hit;
7633e12c5d1SDavid du Colombier 	int w, wasblank;
7643e12c5d1SDavid du Colombier 	Rune r;
7653e12c5d1SDavid du Colombier 
7663e12c5d1SDavid du Colombier 	wasblank = 1;
7673e12c5d1SDavid du Colombier 	hit = 0;
7683e12c5d1SDavid du Colombier 	word = 0;
7693e12c5d1SDavid du Colombier 	for(s=line; *s; s+=w){
7703e12c5d1SDavid du Colombier 		w = chartorune(&r, s);
7717dd7cddfSDavid du Colombier 		x += runestringnwidth(font, &r, 1);
7723e12c5d1SDavid du Colombier 		if(wasblank && r!=' ')
7733e12c5d1SDavid du Colombier 			word = s;
7743e12c5d1SDavid du Colombier 		wasblank = 0;
7753e12c5d1SDavid du Colombier 		if(r == ' '){
7763e12c5d1SDavid du Colombier 			if(x >= p.x)
7773e12c5d1SDavid du Colombier 				break;
7783e12c5d1SDavid du Colombier 			wasblank = 1;
7793e12c5d1SDavid du Colombier 		}
7803e12c5d1SDavid du Colombier 		if(r == ':')
7813e12c5d1SDavid du Colombier 			hit = word;
7823e12c5d1SDavid du Colombier 	}
7833e12c5d1SDavid du Colombier 	if(x < p.x)
7843e12c5d1SDavid du Colombier 		return 0;
7853e12c5d1SDavid du Colombier 	c = utfrune(hit, ':');
7863e12c5d1SDavid du Colombier 	strncpy(buf, hit, c-hit);
7873e12c5d1SDavid du Colombier 	buf[c-hit] = 0;
7883e12c5d1SDavid du Colombier 	return 1;
7893e12c5d1SDavid du Colombier }
7903e12c5d1SDavid du Colombier 
7913e12c5d1SDavid du Colombier int
attext(Thing * t,Point p,char * buf)7923e12c5d1SDavid du Colombier attext(Thing *t, Point p, char *buf)
7933e12c5d1SDavid du Colombier {
7943e12c5d1SDavid du Colombier 	char l0[256], l1[256];
7953e12c5d1SDavid du Colombier 
7963e12c5d1SDavid du Colombier 	if(!ptinrect(p, t->tr))
7973e12c5d1SDavid du Colombier 		return 0;
7983e12c5d1SDavid du Colombier 	stext(t, l0, l1);
7993e12c5d1SDavid du Colombier 	if(p.y < t->tr.min.y+font->height)
8003e12c5d1SDavid du Colombier 		return atline(t->r.min.x, p, l0, buf);
8013e12c5d1SDavid du Colombier 	else
8023e12c5d1SDavid du Colombier 		return atline(t->r.min.x, p, l1, buf);
8033e12c5d1SDavid du Colombier }
8043e12c5d1SDavid du Colombier 
8053e12c5d1SDavid du Colombier int
type(char * buf,char * tag)8063e12c5d1SDavid du Colombier type(char *buf, char *tag)
8073e12c5d1SDavid du Colombier {
8083e12c5d1SDavid du Colombier 	Rune r;
8093e12c5d1SDavid du Colombier 	char *p;
8103e12c5d1SDavid du Colombier 
8117dd7cddfSDavid du Colombier 	esetcursor(&busy);
8123e12c5d1SDavid du Colombier 	p = buf;
8133e12c5d1SDavid du Colombier 	for(;;){
8143e12c5d1SDavid du Colombier 		*p = 0;
8153e12c5d1SDavid du Colombier 		mesg("%s: %s", tag, buf);
8163e12c5d1SDavid du Colombier 		r = ekbd();
8173e12c5d1SDavid du Colombier 		switch(r){
8183e12c5d1SDavid du Colombier 		case '\n':
8193e12c5d1SDavid du Colombier 			mesg("");
8207dd7cddfSDavid du Colombier 			esetcursor(0);
8213e12c5d1SDavid du Colombier 			return p-buf;
8223e12c5d1SDavid du Colombier 		case 0x15:	/* control-U */
8233e12c5d1SDavid du Colombier 			p = buf;
8243e12c5d1SDavid du Colombier 			break;
8253e12c5d1SDavid du Colombier 		case '\b':
8263e12c5d1SDavid du Colombier 			if(p > buf)
8273e12c5d1SDavid du Colombier 				--p;
8283e12c5d1SDavid du Colombier 			break;
8293e12c5d1SDavid du Colombier 		default:
8303e12c5d1SDavid du Colombier 			p += runetochar(p, &r);
8313e12c5d1SDavid du Colombier 		}
8323e12c5d1SDavid du Colombier 	}
8333e12c5d1SDavid du Colombier }
8343e12c5d1SDavid du Colombier 
8353e12c5d1SDavid du Colombier void
textedit(Thing * t,char * tag)8363e12c5d1SDavid du Colombier textedit(Thing *t, char *tag)
8373e12c5d1SDavid du Colombier {
8383e12c5d1SDavid du Colombier 	char buf[256];
8393e12c5d1SDavid du Colombier 	char *s;
8407dd7cddfSDavid du Colombier 	Image *b;
8413e12c5d1SDavid du Colombier 	Subfont *f;
8423e12c5d1SDavid du Colombier 	Fontchar *fc, *nfc;
8433e12c5d1SDavid du Colombier 	Rectangle r;
8447dd7cddfSDavid du Colombier 	ulong chan;
8457dd7cddfSDavid du Colombier 	int i, ld, d, w, c, doredraw, fdx, x;
8463e12c5d1SDavid du Colombier 	Thing *nt;
8473e12c5d1SDavid du Colombier 
8483e12c5d1SDavid du Colombier 	buttons(Up);
8493e12c5d1SDavid du Colombier 	if(type(buf, tag) == 0)
8503e12c5d1SDavid du Colombier 		return;
8513e12c5d1SDavid du Colombier 	if(strcmp(tag, "file") == 0){
8523e12c5d1SDavid du Colombier 		for(s=buf; *s; s++)
8533e12c5d1SDavid du Colombier 			if(*s <= ' '){
8543e12c5d1SDavid du Colombier 				mesg("illegal file name");
8553e12c5d1SDavid du Colombier 				return;
8563e12c5d1SDavid du Colombier 			}
8573e12c5d1SDavid du Colombier 		if(strcmp(t->name, buf) != 0){
8583e12c5d1SDavid du Colombier 			if(t->parent)
8593e12c5d1SDavid du Colombier 				t->parent->mod = 1;
8603e12c5d1SDavid du Colombier 			else
8613e12c5d1SDavid du Colombier 				t->mod = 1;
8623e12c5d1SDavid du Colombier 		}
8633e12c5d1SDavid du Colombier 		for(nt=thing; nt; nt=nt->next)
8643e12c5d1SDavid du Colombier 			if(t==nt || t->parent==nt || nt->parent==t){
8653e12c5d1SDavid du Colombier 				free(nt->name);
8663e12c5d1SDavid du Colombier 				nt->name = strdup(buf);
8673e12c5d1SDavid du Colombier 				if(nt->name == 0){
8683e12c5d1SDavid du Colombier 					mesg("malloc failed: %r");
8693e12c5d1SDavid du Colombier 					return;
8703e12c5d1SDavid du Colombier 				}
8713e12c5d1SDavid du Colombier 				text(nt);
8723e12c5d1SDavid du Colombier 			}
8733e12c5d1SDavid du Colombier 		return;
8743e12c5d1SDavid du Colombier 	}
8757dd7cddfSDavid du Colombier 	if(strcmp(tag, "depth") == 0){
8767dd7cddfSDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (d=atoi(buf))<0 || d>8 || log2[d]<0){
8773e12c5d1SDavid du Colombier 			mesg("illegal ldepth");
8783e12c5d1SDavid du Colombier 			return;
8793e12c5d1SDavid du Colombier 		}
8807dd7cddfSDavid du Colombier 		if(d == t->b->depth)
8813e12c5d1SDavid du Colombier 			return;
8823e12c5d1SDavid du Colombier 		if(t->parent)
8833e12c5d1SDavid du Colombier 			t->parent->mod = 1;
8843e12c5d1SDavid du Colombier 		else
8853e12c5d1SDavid du Colombier 			t->mod = 1;
8867dd7cddfSDavid du Colombier 		if(d == 8)
8877dd7cddfSDavid du Colombier 			chan = CMAP8;
8887dd7cddfSDavid du Colombier 		else
8897dd7cddfSDavid du Colombier 			chan = CHAN1(CGrey, d);
8903e12c5d1SDavid du Colombier 		for(nt=thing; nt; nt=nt->next){
8913e12c5d1SDavid du Colombier 			if(nt!=t && nt!=t->parent && nt->parent!=t)
8923e12c5d1SDavid du Colombier 				continue;
8937dd7cddfSDavid du Colombier 			b = allocimage(display, nt->b->r, chan, 0, 0);
8943e12c5d1SDavid du Colombier 			if(b == 0){
8953e12c5d1SDavid du Colombier 	nobmem:
8967dd7cddfSDavid du Colombier 				mesg("image alloc failed: %r");
8973e12c5d1SDavid du Colombier 				return;
8983e12c5d1SDavid du Colombier 			}
8997dd7cddfSDavid du Colombier 			draw(b, b->r, nt->b, nil, nt->b->r.min);
9007dd7cddfSDavid du Colombier 			freeimage(nt->b);
9013e12c5d1SDavid du Colombier 			nt->b = b;
9023e12c5d1SDavid du Colombier 			if(nt->s){
9037dd7cddfSDavid du Colombier 				b = allocimage(display, nt->b->r, chan, 0, -1);
9043e12c5d1SDavid du Colombier 				if(b == 0)
9053e12c5d1SDavid du Colombier 					goto nobmem;
9067dd7cddfSDavid du Colombier 				draw(b, b->r, nt->b, nil, nt->b->r.min);
9077dd7cddfSDavid du Colombier 				f = allocsubfont(t->name, nt->s->n, nt->s->height, nt->s->ascent, nt->s->info, b);
9083e12c5d1SDavid du Colombier 				if(f == 0){
9093e12c5d1SDavid du Colombier 	nofmem:
9107dd7cddfSDavid du Colombier 					freeimage(b);
9113e12c5d1SDavid du Colombier 					mesg("can't make subfont: %r");
9123e12c5d1SDavid du Colombier 					return;
9133e12c5d1SDavid du Colombier 				}
9147dd7cddfSDavid du Colombier 				nt->s->info = 0;	/* prevent it being freed */
9157dd7cddfSDavid du Colombier 				nt->s->bits = 0;
9167dd7cddfSDavid du Colombier 				freesubfont(nt->s);
9173e12c5d1SDavid du Colombier 				nt->s = f;
9183e12c5d1SDavid du Colombier 			}
9197dd7cddfSDavid du Colombier 			drawthing(nt, 0);
9203e12c5d1SDavid du Colombier 		}
9213e12c5d1SDavid du Colombier 		return;
9223e12c5d1SDavid du Colombier 	}
9233e12c5d1SDavid du Colombier 	if(strcmp(tag, "mag") == 0){
9243e12c5d1SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<=0 || ld>Maxmag){
9253e12c5d1SDavid du Colombier 			mesg("illegal magnification");
9263e12c5d1SDavid du Colombier 			return;
9273e12c5d1SDavid du Colombier 		}
9283e12c5d1SDavid du Colombier 		if(t->mag == ld)
9293e12c5d1SDavid du Colombier 			return;
9303e12c5d1SDavid du Colombier 		t->mag = ld;
9313e12c5d1SDavid du Colombier 		redraw(t);
9323e12c5d1SDavid du Colombier 		return;
9333e12c5d1SDavid du Colombier 	}
9347dd7cddfSDavid du Colombier 	if(strcmp(tag, "r") == 0){
9357dd7cddfSDavid du Colombier 		if(t->s){
9367dd7cddfSDavid du Colombier 			mesg("can't change rectangle of subfont\n");
9377dd7cddfSDavid du Colombier 			return;
9387dd7cddfSDavid du Colombier 		}
9397dd7cddfSDavid du Colombier 		s = buf;
9407dd7cddfSDavid du Colombier 		r.min.x = strtoul(s, &s, 0);
9417dd7cddfSDavid du Colombier 		r.min.y = strtoul(s, &s, 0);
9427dd7cddfSDavid du Colombier 		r.max.x = strtoul(s, &s, 0);
9437dd7cddfSDavid du Colombier 		r.max.y = strtoul(s, &s, 0);
9447dd7cddfSDavid du Colombier 		if(Dx(r)<=0 || Dy(r)<=0){
9457dd7cddfSDavid du Colombier 			mesg("illegal rectangle");
9467dd7cddfSDavid du Colombier 			return;
9477dd7cddfSDavid du Colombier 		}
9487dd7cddfSDavid du Colombier 		if(t->parent)
9497dd7cddfSDavid du Colombier 			t = t->parent;
9507dd7cddfSDavid du Colombier 		for(nt=thing; nt; nt=nt->next){
9517dd7cddfSDavid du Colombier 			if(nt->parent==t && !rectinrect(nt->b->r, r))
9527dd7cddfSDavid du Colombier 				tclose1(nt);
9537dd7cddfSDavid du Colombier 		}
9547dd7cddfSDavid du Colombier 		b = allocimage(display, r, t->b->chan, 0, 0);
9557dd7cddfSDavid du Colombier 		if(b == 0)
9567dd7cddfSDavid du Colombier 			goto nobmem;
9577dd7cddfSDavid du Colombier 		draw(b, r, t->b, nil, r.min);
9587dd7cddfSDavid du Colombier 		freeimage(t->b);
9597dd7cddfSDavid du Colombier 		t->b = b;
9607dd7cddfSDavid du Colombier 		b = allocimage(display, r, t->b->chan, 0, 0);
9617dd7cddfSDavid du Colombier 		if(b == 0)
9627dd7cddfSDavid du Colombier 			goto nobmem;
9637dd7cddfSDavid du Colombier 		redraw(t);
9647dd7cddfSDavid du Colombier 		t->mod = 1;
9657dd7cddfSDavid du Colombier 		return;
9667dd7cddfSDavid du Colombier 	}
9673e12c5d1SDavid du Colombier 	if(strcmp(tag, "ascent") == 0){
9683e12c5d1SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0 || ld>t->s->height){
9693e12c5d1SDavid du Colombier 			mesg("illegal ascent");
9703e12c5d1SDavid du Colombier 			return;
9713e12c5d1SDavid du Colombier 		}
9723e12c5d1SDavid du Colombier 		if(t->s->ascent == ld)
9733e12c5d1SDavid du Colombier 			return;
9743e12c5d1SDavid du Colombier 		t->s->ascent = ld;
9753e12c5d1SDavid du Colombier 		text(t);
9763e12c5d1SDavid du Colombier 		t->mod = 1;
9773e12c5d1SDavid du Colombier 		return;
9783e12c5d1SDavid du Colombier 	}
9793e12c5d1SDavid du Colombier 	if(strcmp(tag, "height") == 0){
9803e12c5d1SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0){
9813e12c5d1SDavid du Colombier 			mesg("illegal height");
9823e12c5d1SDavid du Colombier 			return;
9833e12c5d1SDavid du Colombier 		}
9843e12c5d1SDavid du Colombier 		if(t->s->height == ld)
9853e12c5d1SDavid du Colombier 			return;
9863e12c5d1SDavid du Colombier 		t->s->height = ld;
9873e12c5d1SDavid du Colombier 		text(t);
9883e12c5d1SDavid du Colombier 		t->mod = 1;
9893e12c5d1SDavid du Colombier 		return;
9903e12c5d1SDavid du Colombier 	}
9913e12c5d1SDavid du Colombier 	if(strcmp(tag, "left")==0 || strcmp(tag, "width") == 0){
9923e12c5d1SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0){
9933e12c5d1SDavid du Colombier 			mesg("illegal value");
9943e12c5d1SDavid du Colombier 			return;
9953e12c5d1SDavid du Colombier 		}
9963e12c5d1SDavid du Colombier 		fc = &t->parent->s->info[t->c];
9973e12c5d1SDavid du Colombier 		if(strcmp(tag, "left")==0){
9983e12c5d1SDavid du Colombier 			if(fc->left == ld)
9993e12c5d1SDavid du Colombier 				return;
10003e12c5d1SDavid du Colombier 			fc->left = ld;
10013e12c5d1SDavid du Colombier 		}else{
10023e12c5d1SDavid du Colombier 			if(fc->width == ld)
10033e12c5d1SDavid du Colombier 				return;
10043e12c5d1SDavid du Colombier 			fc->width = ld;
10053e12c5d1SDavid du Colombier 		}
10063e12c5d1SDavid du Colombier 		text(t);
10073e12c5d1SDavid du Colombier 		t->parent->mod = 1;
10083e12c5d1SDavid du Colombier 		return;
10093e12c5d1SDavid du Colombier 	}
10103e12c5d1SDavid du Colombier 	if(strcmp(tag, "offset(hex)") == 0){
10113e12c5d1SDavid du Colombier 		if(!strchr(hex, buf[0])){
10123e12c5d1SDavid du Colombier 	illoff:
10133e12c5d1SDavid du Colombier 			mesg("illegal offset");
10143e12c5d1SDavid du Colombier 			return;
10153e12c5d1SDavid du Colombier 		}
10163e12c5d1SDavid du Colombier 		s = 0;
10173e12c5d1SDavid du Colombier 		ld = strtoul(buf, &s, 16);
10183e12c5d1SDavid du Colombier 		if(*s)
10193e12c5d1SDavid du Colombier 			goto illoff;
10203e12c5d1SDavid du Colombier 		t->off = ld;
10213e12c5d1SDavid du Colombier 		text(t);
10223e12c5d1SDavid du Colombier 		for(nt=thing; nt; nt=nt->next)
10233e12c5d1SDavid du Colombier 			if(nt->parent == t)
10243e12c5d1SDavid du Colombier 				text(nt);
10253e12c5d1SDavid du Colombier 		return;
10263e12c5d1SDavid du Colombier 	}
10273e12c5d1SDavid du Colombier 	if(strcmp(tag, "n") == 0){
10283e12c5d1SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (w=atoi(buf))<=0){
10293e12c5d1SDavid du Colombier 			mesg("illegal n");
10303e12c5d1SDavid du Colombier 			return;
10313e12c5d1SDavid du Colombier 		}
10323e12c5d1SDavid du Colombier 		f = t->s;
10333e12c5d1SDavid du Colombier 		if(w == f->n)
10343e12c5d1SDavid du Colombier 			return;
10353e12c5d1SDavid du Colombier 		doredraw = 0;
10363e12c5d1SDavid du Colombier 	again:
10373e12c5d1SDavid du Colombier 		for(nt=thing; nt; nt=nt->next)
10383e12c5d1SDavid du Colombier 			if(nt->parent == t){
10393e12c5d1SDavid du Colombier 				doredraw = 1;
10403e12c5d1SDavid du Colombier 				tclose1(nt);
10413e12c5d1SDavid du Colombier 				goto again;
10423e12c5d1SDavid du Colombier 			}
10433e12c5d1SDavid du Colombier 		r = t->b->r;
10443e12c5d1SDavid du Colombier 		if(w < f->n)
10453e12c5d1SDavid du Colombier 			r.max.x = f->info[w].x;
10467dd7cddfSDavid du Colombier 		b = allocimage(display, r, t->b->chan, 0, 0);
10473e12c5d1SDavid du Colombier 		if(b == 0)
10483e12c5d1SDavid du Colombier 			goto nobmem;
10497dd7cddfSDavid du Colombier 		draw(b, b->r, t->b, nil, r.min);
10503e12c5d1SDavid du Colombier 		fdx = Dx(editr) - 2*Border;
10513e12c5d1SDavid du Colombier 		if(Dx(t->b->r)/fdx != Dx(b->r)/fdx)
10523e12c5d1SDavid du Colombier 			doredraw = 1;
10537dd7cddfSDavid du Colombier 		freeimage(t->b);
10543e12c5d1SDavid du Colombier 		t->b = b;
10557dd7cddfSDavid du Colombier 		b = allocimage(display, r, t->b->chan, 0, 0);
10563e12c5d1SDavid du Colombier 		if(b == 0)
10573e12c5d1SDavid du Colombier 			goto nobmem;
10587dd7cddfSDavid du Colombier 		draw(b, b->r, t->b, nil, r.min);
10593e12c5d1SDavid du Colombier 		nfc = malloc((w+1)*sizeof(Fontchar));
10603e12c5d1SDavid du Colombier 		if(nfc == 0){
10613e12c5d1SDavid du Colombier 			mesg("malloc failed");
10627dd7cddfSDavid du Colombier 			freeimage(b);
10633e12c5d1SDavid du Colombier 			return;
10643e12c5d1SDavid du Colombier 		}
10653e12c5d1SDavid du Colombier 		fc = f->info;
10663e12c5d1SDavid du Colombier 		for(i=0; i<=w && i<=f->n; i++)
10673e12c5d1SDavid du Colombier 			nfc[i] = fc[i];
10683e12c5d1SDavid du Colombier 		if(w+1 < i)
10693e12c5d1SDavid du Colombier 			memset(nfc+i, 0, ((w+1)-i)*sizeof(Fontchar));
10703e12c5d1SDavid du Colombier 		x = fc[f->n].x;
10713e12c5d1SDavid du Colombier 		for(; i<=w; i++)
10723e12c5d1SDavid du Colombier 			nfc[i].x = x;
10737dd7cddfSDavid du Colombier 		f = allocsubfont(t->name, w, f->height, f->ascent, nfc, b);
10743e12c5d1SDavid du Colombier 		if(f == 0)
10753e12c5d1SDavid du Colombier 			goto nofmem;
10767dd7cddfSDavid du Colombier 		t->s->bits = nil;	/* don't free it */
10777dd7cddfSDavid du Colombier 		freesubfont(t->s);
10783e12c5d1SDavid du Colombier 		f->info = nfc;
10793e12c5d1SDavid du Colombier 		t->s = f;
10803e12c5d1SDavid du Colombier 		if(doredraw)
10813e12c5d1SDavid du Colombier 			redraw(thing);
10823e12c5d1SDavid du Colombier 		else
10837dd7cddfSDavid du Colombier 			drawthing(t, 0);
10843e12c5d1SDavid du Colombier 		t->mod = 1;
10853e12c5d1SDavid du Colombier 		return;
10863e12c5d1SDavid du Colombier 	}
10873e12c5d1SDavid du Colombier 	if(strcmp(tag, "iwidth") == 0){
10883e12c5d1SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (w=atoi(buf))<0){
10893e12c5d1SDavid du Colombier 			mesg("illegal iwidth");
10903e12c5d1SDavid du Colombier 			return;
10913e12c5d1SDavid du Colombier 		}
10923e12c5d1SDavid du Colombier 		w -= Dx(t->b->r);
10933e12c5d1SDavid du Colombier 		if(w == 0)
10943e12c5d1SDavid du Colombier 			return;
10953e12c5d1SDavid du Colombier 		r = t->parent->b->r;
10963e12c5d1SDavid du Colombier 		r.max.x += w;
10973e12c5d1SDavid du Colombier 		c = t->c;
10983e12c5d1SDavid du Colombier 		t = t->parent;
10993e12c5d1SDavid du Colombier 		f = t->s;
11007dd7cddfSDavid du Colombier 		b = allocimage(display, r, t->b->chan, 0, 0);
11013e12c5d1SDavid du Colombier 		if(b == 0)
11023e12c5d1SDavid du Colombier 			goto nobmem;
11033e12c5d1SDavid du Colombier 		fc = &f->info[c];
11047dd7cddfSDavid du Colombier 		draw(b, Rect(b->r.min.x, b->r.min.y,
11057dd7cddfSDavid du Colombier 				b->r.min.x+(fc[1].x-t->b->r.min.x), b->r.min.y+Dy(t->b->r)),
11067dd7cddfSDavid du Colombier 				t->b, nil, t->b->r.min);
11077dd7cddfSDavid du Colombier 		draw(b, Rect(fc[1].x+w, b->r.min.y, w+t->b->r.max.x, b->r.min.y+Dy(t->b->r)),
11087dd7cddfSDavid du Colombier 			t->b, nil, Pt(fc[1].x, t->b->r.min.y));
11093e12c5d1SDavid du Colombier 		fdx = Dx(editr) - 2*Border;
11103e12c5d1SDavid du Colombier 		doredraw = 0;
11113e12c5d1SDavid du Colombier 		if(Dx(t->b->r)/fdx != Dx(b->r)/fdx)
11123e12c5d1SDavid du Colombier 			doredraw = 1;
11137dd7cddfSDavid du Colombier 		freeimage(t->b);
11143e12c5d1SDavid du Colombier 		t->b = b;
11157dd7cddfSDavid du Colombier 		b = allocimage(display, r, t->b->chan, 0, 0);
11163e12c5d1SDavid du Colombier 		if(b == 0)
11173e12c5d1SDavid du Colombier 			goto nobmem;
11187dd7cddfSDavid du Colombier 		draw(b, b->r, t->b, nil, t->b->r.min);
11193e12c5d1SDavid du Colombier 		fc = &f->info[c+1];
11203e12c5d1SDavid du Colombier 		for(i=c+1; i<=f->n; i++, fc++)
11213e12c5d1SDavid du Colombier 			fc->x += w;
11227dd7cddfSDavid du Colombier 		f = allocsubfont(t->name, f->n, f->height, f->ascent,
11237dd7cddfSDavid du Colombier 			f->info, b);
11243e12c5d1SDavid du Colombier 		if(f == 0)
11253e12c5d1SDavid du Colombier 			goto nofmem;
11263e12c5d1SDavid du Colombier 		/* t->s and f share info; free carefully */
11273e12c5d1SDavid du Colombier 		fc = f->info;
11287dd7cddfSDavid du Colombier 		t->s->bits = nil;
11293e12c5d1SDavid du Colombier 		t->s->info = 0;
11307dd7cddfSDavid du Colombier 		freesubfont(t->s);
11313e12c5d1SDavid du Colombier 		f->info = fc;
11323e12c5d1SDavid du Colombier 		t->s = f;
11333e12c5d1SDavid du Colombier 		if(doredraw)
11343e12c5d1SDavid du Colombier 			redraw(t);
11353e12c5d1SDavid du Colombier 		else
11367dd7cddfSDavid du Colombier 			drawthing(t, 0);
11373e12c5d1SDavid du Colombier 		/* redraw all affected chars */
11383e12c5d1SDavid du Colombier 		for(nt=thing; nt; nt=nt->next){
11393e12c5d1SDavid du Colombier 			if(nt->parent!=t || nt->c<c)
11403e12c5d1SDavid du Colombier 				continue;
11413e12c5d1SDavid du Colombier 			fc = &f->info[nt->c];
11423e12c5d1SDavid du Colombier 			r.min.x = fc[0].x;
11433e12c5d1SDavid du Colombier 			r.min.y = nt->b->r.min.y;
11443e12c5d1SDavid du Colombier 			r.max.x = fc[1].x;
11453e12c5d1SDavid du Colombier 			r.max.y = nt->b->r.max.y;
11467dd7cddfSDavid du Colombier 			b = allocimage(display, r, nt->b->chan, 0, 0);
11473e12c5d1SDavid du Colombier 			if(b == 0)
11483e12c5d1SDavid du Colombier 				goto nobmem;
11497dd7cddfSDavid du Colombier 			draw(b, r, t->b, nil, r.min);
11503e12c5d1SDavid du Colombier 			doredraw = 0;
11513e12c5d1SDavid du Colombier 			if(Dx(nt->b->r)/fdx != Dx(b->r)/fdx)
11523e12c5d1SDavid du Colombier 				doredraw = 1;
11537dd7cddfSDavid du Colombier 			freeimage(nt->b);
11543e12c5d1SDavid du Colombier 			nt->b = b;
11553e12c5d1SDavid du Colombier 			if(c != nt->c)
11563e12c5d1SDavid du Colombier 				text(nt);
11573e12c5d1SDavid du Colombier 			else{
11583e12c5d1SDavid du Colombier 				if(doredraw)
11593e12c5d1SDavid du Colombier 					redraw(nt);
11603e12c5d1SDavid du Colombier 				else
11617dd7cddfSDavid du Colombier 					drawthing(nt, 0);
11623e12c5d1SDavid du Colombier 			}
11633e12c5d1SDavid du Colombier 		}
11643e12c5d1SDavid du Colombier 		t->mod = 1;
11653e12c5d1SDavid du Colombier 		return;
11663e12c5d1SDavid du Colombier 	}
11673e12c5d1SDavid du Colombier 	mesg("cannot edit %s in file %s", tag, t->name);
11683e12c5d1SDavid du Colombier }
11693e12c5d1SDavid du Colombier 
11703e12c5d1SDavid du Colombier void
cntledit(char * tag)11713e12c5d1SDavid du Colombier cntledit(char *tag)
11723e12c5d1SDavid du Colombier {
11733e12c5d1SDavid du Colombier 	char buf[256];
117422a127bbSDavid du Colombier 	long l;
11753e12c5d1SDavid du Colombier 
11763e12c5d1SDavid du Colombier 	buttons(Up);
11773e12c5d1SDavid du Colombier 	if(type(buf, tag) == 0)
11783e12c5d1SDavid du Colombier 		return;
11793e12c5d1SDavid du Colombier 	if(strcmp(tag, "mag") == 0){
11803e12c5d1SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (l=atoi(buf))<=0 || l>Maxmag){
11813e12c5d1SDavid du Colombier 			mesg("illegal magnification");
11823e12c5d1SDavid du Colombier 			return;
11833e12c5d1SDavid du Colombier 		}
11843e12c5d1SDavid du Colombier 		mag = l;
11853e12c5d1SDavid du Colombier 		cntl();
11863e12c5d1SDavid du Colombier 		return;
11873e12c5d1SDavid du Colombier 	}
11883e12c5d1SDavid du Colombier 	if(strcmp(tag, "but1")==0
11897dd7cddfSDavid du Colombier 	|| strcmp(tag, "but2")==0){
11907dd7cddfSDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0] || (l=atoi(buf))<0 || l>255){
11917dd7cddfSDavid du Colombier 			mesg("illegal value");
11923e12c5d1SDavid du Colombier 			return;
11933e12c5d1SDavid du Colombier 		}
11943e12c5d1SDavid du Colombier 		if(strcmp(tag, "but1") == 0)
11957dd7cddfSDavid du Colombier 			but1val = l;
11963e12c5d1SDavid du Colombier 		else if(strcmp(tag, "but2") == 0)
11977dd7cddfSDavid du Colombier 			but2val = l;
11987dd7cddfSDavid du Colombier 		cntl();
11997dd7cddfSDavid du Colombier 		return;
12007dd7cddfSDavid du Colombier 	}
12017dd7cddfSDavid du Colombier 	if(strcmp(tag, "invert-on-copy")==0){
12027dd7cddfSDavid du Colombier 		if(buf[0]=='y' || buf[0]=='1')
12037dd7cddfSDavid du Colombier 			invert = 1;
12047dd7cddfSDavid du Colombier 		else if(buf[0]=='n' || buf[0]=='0')
12057dd7cddfSDavid du Colombier 			invert = 0;
12067dd7cddfSDavid du Colombier 		else{
12077dd7cddfSDavid du Colombier 			mesg("illegal value");
12087dd7cddfSDavid du Colombier 			return;
12097dd7cddfSDavid du Colombier 		}
12103e12c5d1SDavid du Colombier 		cntl();
12113e12c5d1SDavid du Colombier 		return;
12123e12c5d1SDavid du Colombier 	}
12133e12c5d1SDavid du Colombier 	mesg("cannot edit %s", tag);
12143e12c5d1SDavid du Colombier }
12153e12c5d1SDavid du Colombier 
12163e12c5d1SDavid du Colombier void
buttons(int ud)12173e12c5d1SDavid du Colombier buttons(int ud)
12183e12c5d1SDavid du Colombier {
12193e12c5d1SDavid du Colombier 	while((mouse.buttons==0) != ud)
12203e12c5d1SDavid du Colombier 		mouse = emouse();
12213e12c5d1SDavid du Colombier }
12223e12c5d1SDavid du Colombier 
12237dd7cddfSDavid du Colombier Point
screenpt(Thing * t,Point realp)12247dd7cddfSDavid du Colombier screenpt(Thing *t, Point realp)
12253e12c5d1SDavid du Colombier {
12267dd7cddfSDavid du Colombier 	int fdx, n;
12273e12c5d1SDavid du Colombier 	Point p;
12283e12c5d1SDavid du Colombier 
12297dd7cddfSDavid du Colombier 	fdx = Dx(editr)-2*Border;
12307dd7cddfSDavid du Colombier 	if(t->mag > 1)
12317dd7cddfSDavid du Colombier 		fdx -= fdx%t->mag;
12327dd7cddfSDavid du Colombier 	p = mulpt(subpt(realp, t->b->r.min), t->mag);
12337dd7cddfSDavid du Colombier 	if(fdx < Dx(t->b->r)*t->mag){
12347dd7cddfSDavid du Colombier 		n = p.x/fdx;
12357dd7cddfSDavid du Colombier 		p.y += n * (Dy(t->b->r)*t->mag+Border);
12367dd7cddfSDavid du Colombier 		p.x -= n * fdx;
12377dd7cddfSDavid du Colombier 	}
12387dd7cddfSDavid du Colombier 	p = addpt(p, t->r.min);
12397dd7cddfSDavid du Colombier 	return p;
12407dd7cddfSDavid du Colombier }
12417dd7cddfSDavid du Colombier 
12427dd7cddfSDavid du Colombier Point
realpt(Thing * t,Point screenp)12437dd7cddfSDavid du Colombier realpt(Thing *t, Point screenp)
12447dd7cddfSDavid du Colombier {
12457dd7cddfSDavid du Colombier 	int fdx, n, dy;
12467dd7cddfSDavid du Colombier 	Point p;
12477dd7cddfSDavid du Colombier 
12487dd7cddfSDavid du Colombier 	fdx = (Dx(editr)-2*Border);
12497dd7cddfSDavid du Colombier 	if(t->mag > 1)
12507dd7cddfSDavid du Colombier 		fdx -= fdx%t->mag;
12517dd7cddfSDavid du Colombier 	p.y = screenp.y-t->r.min.y;
12527dd7cddfSDavid du Colombier 	p.x = 0;
12537dd7cddfSDavid du Colombier 	if(fdx < Dx(t->b->r)*t->mag){
12547dd7cddfSDavid du Colombier 		dy = Dy(t->b->r)*t->mag+Border;
12557dd7cddfSDavid du Colombier 		n = (p.y/dy);
12567dd7cddfSDavid du Colombier 		p.x = n * fdx;
12577dd7cddfSDavid du Colombier 		p.y -= n * dy;
12587dd7cddfSDavid du Colombier 	}
12597dd7cddfSDavid du Colombier 	p.x += screenp.x-t->r.min.x;
12607dd7cddfSDavid du Colombier 	p = addpt(divpt(p, t->mag), t->b->r.min);
12617dd7cddfSDavid du Colombier 	return p;
12627dd7cddfSDavid du Colombier }
12637dd7cddfSDavid du Colombier 
12647dd7cddfSDavid du Colombier int
sweep(int but,Rectangle * r)12657dd7cddfSDavid du Colombier sweep(int but, Rectangle *r)
12667dd7cddfSDavid du Colombier {
12677dd7cddfSDavid du Colombier 	Thing *t;
12687dd7cddfSDavid du Colombier 	Point p, q, lastq;
12697dd7cddfSDavid du Colombier 
12707dd7cddfSDavid du Colombier 	esetcursor(&sweep0);
12713e12c5d1SDavid du Colombier 	buttons(Down);
12727dd7cddfSDavid du Colombier 	if(mouse.buttons != (1<<(but-1))){
12733e12c5d1SDavid du Colombier 		buttons(Up);
12747dd7cddfSDavid du Colombier 		esetcursor(0);
12753e12c5d1SDavid du Colombier 		return 0;
12763e12c5d1SDavid du Colombier 	}
12773e12c5d1SDavid du Colombier 	p = mouse.xy;
12787dd7cddfSDavid du Colombier 	for(t=thing; t; t=t->next)
12797dd7cddfSDavid du Colombier 		if(ptinrect(p, t->r))
12807dd7cddfSDavid du Colombier 			break;
12817dd7cddfSDavid du Colombier 	if(t)
12827dd7cddfSDavid du Colombier 		p = screenpt(t, realpt(t, p));
12833e12c5d1SDavid du Colombier 	r->min = p;
12843e12c5d1SDavid du Colombier 	r->max = p;
12857dd7cddfSDavid du Colombier 	esetcursor(&box);
12867dd7cddfSDavid du Colombier 	lastq = ZP;
12877dd7cddfSDavid du Colombier 	while(mouse.buttons == (1<<(but-1))){
12887dd7cddfSDavid du Colombier 		edrawgetrect(insetrect(*r, -Borderwidth), 1);
12893e12c5d1SDavid du Colombier 		mouse = emouse();
12907dd7cddfSDavid du Colombier 		edrawgetrect(insetrect(*r, -Borderwidth), 0);
12917dd7cddfSDavid du Colombier 		q = mouse.xy;
12927dd7cddfSDavid du Colombier 		if(t)
12937dd7cddfSDavid du Colombier 			q = screenpt(t, realpt(t, q));
12947dd7cddfSDavid du Colombier 		if(eqpt(q, lastq))
12957dd7cddfSDavid du Colombier 			continue;
12967dd7cddfSDavid du Colombier 		*r = canonrect(Rpt(p, q));
12977dd7cddfSDavid du Colombier 		lastq = q;
12983e12c5d1SDavid du Colombier 	}
12997dd7cddfSDavid du Colombier 	esetcursor(0);
13003e12c5d1SDavid du Colombier 	if(mouse.buttons){
13013e12c5d1SDavid du Colombier 		buttons(Up);
13023e12c5d1SDavid du Colombier 		return 0;
13033e12c5d1SDavid du Colombier 	}
13043e12c5d1SDavid du Colombier 	return 1;
13053e12c5d1SDavid du Colombier }
13063e12c5d1SDavid du Colombier 
13073e12c5d1SDavid du Colombier void
openedit(Thing * t,Point pt,int c)13083e12c5d1SDavid du Colombier openedit(Thing *t, Point pt, int c)
13093e12c5d1SDavid du Colombier {
13103e12c5d1SDavid du Colombier 	int x, y;
13113e12c5d1SDavid du Colombier 	Point p;
13123e12c5d1SDavid du Colombier 	Rectangle r;
13133e12c5d1SDavid du Colombier 	Rectangle br;
13143e12c5d1SDavid du Colombier 	Fontchar *fc;
13153e12c5d1SDavid du Colombier 	Thing *nt;
13163e12c5d1SDavid du Colombier 
13177dd7cddfSDavid du Colombier 	if(t->b->depth > 8){
13187dd7cddfSDavid du Colombier 		mesg("image has depth %d; can't handle >8", t->b->depth);
13197dd7cddfSDavid du Colombier 		return;
13207dd7cddfSDavid du Colombier 	}
13213e12c5d1SDavid du Colombier 	br = t->b->r;
13223e12c5d1SDavid du Colombier 	if(t->s == 0){
13233e12c5d1SDavid du Colombier 		c = -1;
13243e12c5d1SDavid du Colombier 		/* if big enough to bother, sweep box */
13253e12c5d1SDavid du Colombier 		if(Dx(br)<=16 && Dy(br)<=16)
13263e12c5d1SDavid du Colombier 			r = br;
13273e12c5d1SDavid du Colombier 		else{
13283e12c5d1SDavid du Colombier 			if(!sweep(1, &r))
13293e12c5d1SDavid du Colombier 				return;
13307dd7cddfSDavid du Colombier 			r = rectaddpt(r, subpt(br.min, t->r.min));
13313e12c5d1SDavid du Colombier 			if(!rectclip(&r, br))
13323e12c5d1SDavid du Colombier 				return;
13333e12c5d1SDavid du Colombier 			if(Dx(br) <= 8){
13343e12c5d1SDavid du Colombier 				r.min.x = br.min.x;
13353e12c5d1SDavid du Colombier 				r.max.x = br.max.x;
13363e12c5d1SDavid du Colombier 			}else if(Dx(r) < 4){
13373e12c5d1SDavid du Colombier 	    toosmall:
13383e12c5d1SDavid du Colombier 				mesg("rectangle too small");
13393e12c5d1SDavid du Colombier 				return;
13403e12c5d1SDavid du Colombier 			}
13413e12c5d1SDavid du Colombier 			if(Dy(br) <= 8){
13423e12c5d1SDavid du Colombier 				r.min.y = br.min.y;
13433e12c5d1SDavid du Colombier 				r.max.y = br.max.y;
13443e12c5d1SDavid du Colombier 			}else if(Dy(r) < 4)
13453e12c5d1SDavid du Colombier 				goto toosmall;
13463e12c5d1SDavid du Colombier 		}
13473e12c5d1SDavid du Colombier 	}else if(c >= 0){
13483e12c5d1SDavid du Colombier 		fc = &t->s->info[c];
13493e12c5d1SDavid du Colombier 		r.min.x = fc[0].x;
13503e12c5d1SDavid du Colombier 		r.min.y = br.min.y;
13513e12c5d1SDavid du Colombier 		r.max.x = fc[1].x;
13523e12c5d1SDavid du Colombier 		r.max.y = br.min.y + Dy(br);
13533e12c5d1SDavid du Colombier 	}else{
13543e12c5d1SDavid du Colombier 		/* just point at character */
13553e12c5d1SDavid du Colombier 		fc = t->s->info;
13567dd7cddfSDavid du Colombier 		p = addpt(pt, subpt(br.min, t->r.min));
13573e12c5d1SDavid du Colombier 		x = br.min.x;
13583e12c5d1SDavid du Colombier 		y = br.min.y;
13593e12c5d1SDavid du Colombier 		for(c=0; c<t->s->n; c++,fc++){
13603e12c5d1SDavid du Colombier 	    again:
13613e12c5d1SDavid du Colombier 			r.min.x = x;
13623e12c5d1SDavid du Colombier 			r.min.y = y;
13633e12c5d1SDavid du Colombier 			r.max.x = x + fc[1].x - fc[0].x;
13643e12c5d1SDavid du Colombier 			r.max.y = y + Dy(br);
13653e12c5d1SDavid du Colombier 			if(ptinrect(p, r))
13663e12c5d1SDavid du Colombier 				goto found;
13673e12c5d1SDavid du Colombier 			if(r.max.x >= br.min.x+Dx(t->r)){
13683e12c5d1SDavid du Colombier 				x -= Dx(t->r);
13693e12c5d1SDavid du Colombier 				y += t->s->height;
13703e12c5d1SDavid du Colombier 				if(fc[1].x > fc[0].x)
13713e12c5d1SDavid du Colombier 					goto again;
13723e12c5d1SDavid du Colombier 			}
13733e12c5d1SDavid du Colombier 			x += fc[1].x - fc[0].x;
13743e12c5d1SDavid du Colombier 		}
13753e12c5d1SDavid du Colombier 		return;
13763e12c5d1SDavid du Colombier 	   found:
13773e12c5d1SDavid du Colombier 		r = br;
13783e12c5d1SDavid du Colombier 		r.min.x = fc[0].x;
13793e12c5d1SDavid du Colombier 		r.max.x = fc[1].x;
13803e12c5d1SDavid du Colombier 	}
13813e12c5d1SDavid du Colombier 	nt = malloc(sizeof(Thing));
13823e12c5d1SDavid du Colombier 	if(nt == 0){
13833e12c5d1SDavid du Colombier    nomem:
13843e12c5d1SDavid du Colombier 		mesg("can't allocate: %r");
13853e12c5d1SDavid du Colombier 		return;
13863e12c5d1SDavid du Colombier 	}
13873e12c5d1SDavid du Colombier 	memset(nt, 0, sizeof(Thing));
13883e12c5d1SDavid du Colombier 	nt->c = c;
13897dd7cddfSDavid du Colombier 	nt->b = allocimage(display, r, t->b->chan, 0, DNofill);
13903e12c5d1SDavid du Colombier 	if(nt->b == 0){
13913e12c5d1SDavid du Colombier 		free(nt);
13923e12c5d1SDavid du Colombier 		goto nomem;
13933e12c5d1SDavid du Colombier 	}
13947dd7cddfSDavid du Colombier 	draw(nt->b, r, t->b, nil, r.min);
13953e12c5d1SDavid du Colombier 	nt->name = strdup(t->name);
13963e12c5d1SDavid du Colombier 	if(nt->name == 0){
13977dd7cddfSDavid du Colombier 		freeimage(nt->b);
13983e12c5d1SDavid du Colombier 		free(nt);
13993e12c5d1SDavid du Colombier 		goto nomem;
14003e12c5d1SDavid du Colombier 	}
14013e12c5d1SDavid du Colombier 	nt->parent = t;
14023e12c5d1SDavid du Colombier 	nt->mag = mag;
14037dd7cddfSDavid du Colombier 	drawthing(nt, 1);
14043e12c5d1SDavid du Colombier }
14053e12c5d1SDavid du Colombier 
14063e12c5d1SDavid du Colombier void
ckinfo(Thing * t,Rectangle mod)14073e12c5d1SDavid du Colombier ckinfo(Thing *t, Rectangle mod)
14083e12c5d1SDavid du Colombier {
14093e12c5d1SDavid du Colombier 	int i, j, k, top, bot, n, zero;
14103e12c5d1SDavid du Colombier 	Fontchar *fc;
14113e12c5d1SDavid du Colombier 	Rectangle r;
14127dd7cddfSDavid du Colombier 	Image *b;
14133e12c5d1SDavid du Colombier 	Thing *nt;
14143e12c5d1SDavid du Colombier 
14153e12c5d1SDavid du Colombier 	if(t->parent)
14163e12c5d1SDavid du Colombier 		t = t->parent;
14173e12c5d1SDavid du Colombier 	if(t->s==0 || Dy(t->b->r)==0)
14183e12c5d1SDavid du Colombier 		return;
14193e12c5d1SDavid du Colombier 	b = 0;
14203e12c5d1SDavid du Colombier 	/* check bounding boxes */
14213e12c5d1SDavid du Colombier 	fc = &t->s->info[0];
14223e12c5d1SDavid du Colombier 	r.min.y = t->b->r.min.y;
14233e12c5d1SDavid du Colombier 	r.max.y = t->b->r.max.y;
14243e12c5d1SDavid du Colombier 	for(i=0; i<t->s->n; i++, fc++){
14253e12c5d1SDavid du Colombier 		r.min.x = fc[0].x;
14263e12c5d1SDavid du Colombier 		r.max.x = fc[1].x;
14273e12c5d1SDavid du Colombier 		if(!rectXrect(mod, r))
14283e12c5d1SDavid du Colombier 			continue;
14293e12c5d1SDavid du Colombier 		if(b==0 || Dx(b->r)<Dx(r)){
14303e12c5d1SDavid du Colombier 			if(b)
14317dd7cddfSDavid du Colombier 				freeimage(b);
14327dd7cddfSDavid du Colombier 			b = allocimage(display, rectsubpt(r, r.min), t->b->chan, 0, 0);
14333e12c5d1SDavid du Colombier 			if(b == 0){
14347dd7cddfSDavid du Colombier 				mesg("can't alloc image");
14353e12c5d1SDavid du Colombier 				break;
14363e12c5d1SDavid du Colombier 			}
14373e12c5d1SDavid du Colombier 		}
14387dd7cddfSDavid du Colombier 		draw(b, b->r, display->white, nil, ZP);
14397dd7cddfSDavid du Colombier 		draw(b, b->r, t->b, nil, r.min);
14403e12c5d1SDavid du Colombier 		top = 100000;
14413e12c5d1SDavid du Colombier 		bot = 0;
14427dd7cddfSDavid du Colombier 		n = 2+((Dx(r)/8)*t->b->depth);
14433e12c5d1SDavid du Colombier 		for(j=0; j<b->r.max.y; j++){
14443e12c5d1SDavid du Colombier 			memset(data, 0, n);
14457dd7cddfSDavid du Colombier 			unloadimage(b, Rect(b->r.min.x, j, b->r.max.x, j+1), data, sizeof data);
14463e12c5d1SDavid du Colombier 			zero = 1;
14473e12c5d1SDavid du Colombier 			for(k=0; k<n; k++)
14483e12c5d1SDavid du Colombier 				if(data[k]){
14493e12c5d1SDavid du Colombier 					zero = 0;
14503e12c5d1SDavid du Colombier 					break;
14513e12c5d1SDavid du Colombier 				}
14523e12c5d1SDavid du Colombier 			if(!zero){
14533e12c5d1SDavid du Colombier 				if(top > j)
14543e12c5d1SDavid du Colombier 					top = j;
14553e12c5d1SDavid du Colombier 				bot = j+1;
14563e12c5d1SDavid du Colombier 			}
14573e12c5d1SDavid du Colombier 		}
14583e12c5d1SDavid du Colombier 		if(top > j)
14593e12c5d1SDavid du Colombier 			top = 0;
14603e12c5d1SDavid du Colombier 		if(top!=fc->top || bot!=fc->bottom){
14613e12c5d1SDavid du Colombier 			fc->top = top;
14623e12c5d1SDavid du Colombier 			fc->bottom = bot;
14633e12c5d1SDavid du Colombier 			for(nt=thing; nt; nt=nt->next)
14643e12c5d1SDavid du Colombier 				if(nt->parent==t && nt->c==i)
14653e12c5d1SDavid du Colombier 					text(nt);
14663e12c5d1SDavid du Colombier 		}
14673e12c5d1SDavid du Colombier 	}
14683e12c5d1SDavid du Colombier 	if(b)
14697dd7cddfSDavid du Colombier 		freeimage(b);
14703e12c5d1SDavid du Colombier }
14713e12c5d1SDavid du Colombier 
14723e12c5d1SDavid du Colombier void
twidpix(Thing * t,Point p,int set)14733e12c5d1SDavid du Colombier twidpix(Thing *t, Point p, int set)
14743e12c5d1SDavid du Colombier {
14757dd7cddfSDavid du Colombier 	Image *b, *v;
14767dd7cddfSDavid du Colombier 	int c;
14773e12c5d1SDavid du Colombier 
14783e12c5d1SDavid du Colombier 	b = t->b;
14793e12c5d1SDavid du Colombier 	if(!ptinrect(p, b->r))
14803e12c5d1SDavid du Colombier 		return;
14817dd7cddfSDavid du Colombier 	if(set)
14827dd7cddfSDavid du Colombier 		c = but1val;
14837dd7cddfSDavid du Colombier 	else
14847dd7cddfSDavid du Colombier 		c = but2val;
14857dd7cddfSDavid du Colombier 	if(b->chan == GREY8)
14867dd7cddfSDavid du Colombier 		v = greyvalues[c];
14877dd7cddfSDavid du Colombier 	else
14887dd7cddfSDavid du Colombier 		v = values[c];
14897dd7cddfSDavid du Colombier 	draw(b, Rect(p.x, p.y, p.x+1, p.y+1), v, nil, ZP);
14903e12c5d1SDavid du Colombier 	p = screenpt(t, p);
14917dd7cddfSDavid du Colombier 	draw(screen, Rect(p.x, p.y, p.x+t->mag, p.y+t->mag), v, nil, ZP);
14923e12c5d1SDavid du Colombier }
14933e12c5d1SDavid du Colombier 
14943e12c5d1SDavid du Colombier void
twiddle(Thing * t)14953e12c5d1SDavid du Colombier twiddle(Thing *t)
14963e12c5d1SDavid du Colombier {
14973e12c5d1SDavid du Colombier 	int set;
14983e12c5d1SDavid du Colombier 	Point p, lastp;
14997dd7cddfSDavid du Colombier 	Image *b;
15003e12c5d1SDavid du Colombier 	Thing *nt;
15013e12c5d1SDavid du Colombier 	Rectangle mod;
15023e12c5d1SDavid du Colombier 
15033e12c5d1SDavid du Colombier 	if(mouse.buttons!=1 && mouse.buttons!=2){
15043e12c5d1SDavid du Colombier 		buttons(Up);
15053e12c5d1SDavid du Colombier 		return;
15063e12c5d1SDavid du Colombier 	}
15073e12c5d1SDavid du Colombier 	set = mouse.buttons==1;
15083e12c5d1SDavid du Colombier 	b = t->b;
15097dd7cddfSDavid du Colombier 	lastp = addpt(b->r.min, Pt(-1, -1));
15107dd7cddfSDavid du Colombier 	mod = Rpt(addpt(b->r.max, Pt(1, 1)), lastp);
15113e12c5d1SDavid du Colombier 	while(mouse.buttons){
15123e12c5d1SDavid du Colombier 		p = realpt(t, mouse.xy);
15133e12c5d1SDavid du Colombier 		if(!eqpt(p, lastp)){
15143e12c5d1SDavid du Colombier 			lastp = p;
15153e12c5d1SDavid du Colombier 			if(ptinrect(p, b->r)){
15163e12c5d1SDavid du Colombier 				for(nt=thing; nt; nt=nt->next)
15173e12c5d1SDavid du Colombier 					if(nt->parent==t->parent || nt==t->parent)
15183e12c5d1SDavid du Colombier 						twidpix(nt, p, set);
15193e12c5d1SDavid du Colombier 				if(t->parent)
15203e12c5d1SDavid du Colombier 					t->parent->mod = 1;
15213e12c5d1SDavid du Colombier 				else
15223e12c5d1SDavid du Colombier 					t->mod = 1;
15233e12c5d1SDavid du Colombier 				if(p.x < mod.min.x)
15243e12c5d1SDavid du Colombier 					mod.min.x = p.x;
15253e12c5d1SDavid du Colombier 				if(p.y < mod.min.y)
15263e12c5d1SDavid du Colombier 					mod.min.y = p.y;
15273e12c5d1SDavid du Colombier 				if(p.x >= mod.max.x)
15283e12c5d1SDavid du Colombier 					mod.max.x = p.x+1;
15293e12c5d1SDavid du Colombier 				if(p.y >= mod.max.y)
15303e12c5d1SDavid du Colombier 					mod.max.y = p.y+1;
15313e12c5d1SDavid du Colombier 			}
15323e12c5d1SDavid du Colombier 		}
15333e12c5d1SDavid du Colombier 		mouse = emouse();
15343e12c5d1SDavid du Colombier 	}
15353e12c5d1SDavid du Colombier 	ckinfo(t, mod);
15363e12c5d1SDavid du Colombier }
15373e12c5d1SDavid du Colombier 
15383e12c5d1SDavid du Colombier void
select(void)15393e12c5d1SDavid du Colombier select(void)
15403e12c5d1SDavid du Colombier {
15413e12c5d1SDavid du Colombier 	Thing *t;
15423e12c5d1SDavid du Colombier 	char line[128], buf[128];
15433e12c5d1SDavid du Colombier 	Point p;
15443e12c5d1SDavid du Colombier 
15453e12c5d1SDavid du Colombier 	if(ptinrect(mouse.xy, cntlr)){
15463e12c5d1SDavid du Colombier 		scntl(line);
15473e12c5d1SDavid du Colombier 		if(atline(cntlr.min.x, mouse.xy, line, buf)){
15483e12c5d1SDavid du Colombier 			if(mouse.buttons == 1)
15493e12c5d1SDavid du Colombier 				cntledit(buf);
15503e12c5d1SDavid du Colombier 			else
15513e12c5d1SDavid du Colombier 				buttons(Up);
15523e12c5d1SDavid du Colombier 			return;
15533e12c5d1SDavid du Colombier 		}
15543e12c5d1SDavid du Colombier 		return;
15553e12c5d1SDavid du Colombier 	}
15563e12c5d1SDavid du Colombier 	for(t=thing; t; t=t->next){
15573e12c5d1SDavid du Colombier 		if(attext(t, mouse.xy, buf)){
15583e12c5d1SDavid du Colombier 			if(mouse.buttons == 1)
15593e12c5d1SDavid du Colombier 				textedit(t, buf);
15603e12c5d1SDavid du Colombier 			else
15613e12c5d1SDavid du Colombier 				buttons(Up);
15623e12c5d1SDavid du Colombier 			return;
15633e12c5d1SDavid du Colombier 		}
15643e12c5d1SDavid du Colombier 		if(ptinrect(mouse.xy, t->r)){
15653e12c5d1SDavid du Colombier 			if(t->parent == 0){
15663e12c5d1SDavid du Colombier 				if(mouse.buttons == 1){
15673e12c5d1SDavid du Colombier 					p = mouse.xy;
15683e12c5d1SDavid du Colombier 					buttons(Up);
15693e12c5d1SDavid du Colombier 					openedit(t, p, -1);
15703e12c5d1SDavid du Colombier 				}else
15713e12c5d1SDavid du Colombier 					buttons(Up);
15723e12c5d1SDavid du Colombier 				return;
15733e12c5d1SDavid du Colombier 			}
15743e12c5d1SDavid du Colombier 			twiddle(t);
15753e12c5d1SDavid du Colombier 			return;
15763e12c5d1SDavid du Colombier 		}
15773e12c5d1SDavid du Colombier 	}
15783e12c5d1SDavid du Colombier }
15793e12c5d1SDavid du Colombier 
15803e12c5d1SDavid du Colombier void
twrite(Thing * t)15813e12c5d1SDavid du Colombier twrite(Thing *t)
15823e12c5d1SDavid du Colombier {
15833e12c5d1SDavid du Colombier 	int i, j, x, y, fd, ws, ld;
15843e12c5d1SDavid du Colombier 	Biobuf buf;
15853e12c5d1SDavid du Colombier 	Rectangle r;
15863e12c5d1SDavid du Colombier 
15873e12c5d1SDavid du Colombier 	if(t->parent)
15883e12c5d1SDavid du Colombier 		t = t->parent;
15897dd7cddfSDavid du Colombier 	esetcursor(&busy);
15903e12c5d1SDavid du Colombier 	fd = create(t->name, OWRITE, 0666);
15913e12c5d1SDavid du Colombier 	if(fd < 0){
15923e12c5d1SDavid du Colombier 		mesg("can't write %s: %r", t->name);
15933e12c5d1SDavid du Colombier 		return;
15943e12c5d1SDavid du Colombier 	}
15959a747e4fSDavid du Colombier 	if(t->face && t->b->depth <= 4){
15963e12c5d1SDavid du Colombier 		r = t->b->r;
15977dd7cddfSDavid du Colombier 		ld = log2[t->b->depth];
15983e12c5d1SDavid du Colombier 		/* This heuristic reflects peculiarly different formats */
15993e12c5d1SDavid du Colombier 		ws = 4;
16007dd7cddfSDavid du Colombier 		if(t->face == 2)	/* cursor file */
16013e12c5d1SDavid du Colombier 			ws = 1;
16023e12c5d1SDavid du Colombier 		else if(Dx(r)<32 || ld==0)
16033e12c5d1SDavid du Colombier 			ws = 2;
16043e12c5d1SDavid du Colombier 		Binit(&buf, fd, OWRITE);
16057dd7cddfSDavid du Colombier 		if(t->face == CURSOR)
16067dd7cddfSDavid du Colombier 			Bprint(&buf, "{");
16073e12c5d1SDavid du Colombier 		for(y=r.min.y; y<r.max.y; y++){
16087dd7cddfSDavid du Colombier 			unloadimage(t->b, Rect(r.min.x, y, r.max.x, y+1), data, sizeof data);
16093e12c5d1SDavid du Colombier 			j = 0;
16103e12c5d1SDavid du Colombier 			for(x=r.min.x; x<r.max.x; j+=ws,x+=ws*8>>ld){
16113e12c5d1SDavid du Colombier 				Bprint(&buf, "0x");
16123e12c5d1SDavid du Colombier 				for(i=0; i<ws; i++)
16133e12c5d1SDavid du Colombier 					Bprint(&buf, "%.2x", data[i+j]);
16143e12c5d1SDavid du Colombier 				Bprint(&buf, ", ");
16153e12c5d1SDavid du Colombier 			}
16167dd7cddfSDavid du Colombier 			if(t->face == CURSOR){
16177dd7cddfSDavid du Colombier 				switch(y){
16187dd7cddfSDavid du Colombier 				case 3: case 7: case 11: case 19: case 23: case 27:
16197dd7cddfSDavid du Colombier 					Bprint(&buf, "\n ");
16207dd7cddfSDavid du Colombier 					break;
16217dd7cddfSDavid du Colombier 				case 15:
16227dd7cddfSDavid du Colombier 					Bprint(&buf, "},\n{");
16237dd7cddfSDavid du Colombier 					break;
16247dd7cddfSDavid du Colombier 				case 31:
16257dd7cddfSDavid du Colombier 					Bprint(&buf, "}\n");
16267dd7cddfSDavid du Colombier 					break;
16277dd7cddfSDavid du Colombier 				}
16287dd7cddfSDavid du Colombier 			}else
16293e12c5d1SDavid du Colombier 				Bprint(&buf, "\n");
16303e12c5d1SDavid du Colombier 		}
1631219b2ee8SDavid du Colombier 		Bterm(&buf);
16327dd7cddfSDavid du Colombier 	}else
16337dd7cddfSDavid du Colombier 		if(writeimage(fd, t->b, 0)<0 || (t->s && writesubfont(fd, t->s)<0)){
16347dd7cddfSDavid du Colombier 			close(fd);
16357dd7cddfSDavid du Colombier 			mesg("can't write %s: %r", t->name);
16363e12c5d1SDavid du Colombier 		}
16373e12c5d1SDavid du Colombier 	t->mod = 0;
16383e12c5d1SDavid du Colombier 	close(fd);
16393e12c5d1SDavid du Colombier 	mesg("wrote %s", t->name);
16403e12c5d1SDavid du Colombier }
16413e12c5d1SDavid du Colombier 
16423e12c5d1SDavid du Colombier void
tpixels(void)16437dd7cddfSDavid du Colombier tpixels(void)
16447dd7cddfSDavid du Colombier {
16457dd7cddfSDavid du Colombier 	Thing *t;
16467dd7cddfSDavid du Colombier 	Point p, lastp;
16477dd7cddfSDavid du Colombier 
16487dd7cddfSDavid du Colombier 	esetcursor(&pixel);
16497dd7cddfSDavid du Colombier 	for(;;){
16507dd7cddfSDavid du Colombier 		buttons(Down);
16517dd7cddfSDavid du Colombier 		if(mouse.buttons != 4)
16527dd7cddfSDavid du Colombier 			break;
16537dd7cddfSDavid du Colombier 		for(t=thing; t; t=t->next){
16547dd7cddfSDavid du Colombier 			lastp = Pt(-1, -1);
16557dd7cddfSDavid du Colombier 			if(ptinrect(mouse.xy, t->r)){
16567dd7cddfSDavid du Colombier 				while(ptinrect(mouse.xy, t->r) && mouse.buttons==4){
16577dd7cddfSDavid du Colombier 					p = realpt(t, mouse.xy);
16587dd7cddfSDavid du Colombier 					if(!eqpt(p, lastp)){
16597dd7cddfSDavid du Colombier 						if(p.y != lastp.y)
16607dd7cddfSDavid du Colombier 							unloadimage(t->b, Rect(t->b->r.min.x, p.y, t->b->r.max.x, p.y+1), data, sizeof data);
16617dd7cddfSDavid du Colombier 						mesg("[%d,%d] = %d=0x%ux", p.x, p.y, value(t->b, p.x), value(t->b, p.x));
16627dd7cddfSDavid du Colombier 						lastp = p;
16637dd7cddfSDavid du Colombier 					}
16647dd7cddfSDavid du Colombier 					mouse = emouse();
16657dd7cddfSDavid du Colombier 				}
16667dd7cddfSDavid du Colombier 				goto Continue;
16677dd7cddfSDavid du Colombier 			}
16687dd7cddfSDavid du Colombier 		}
16697dd7cddfSDavid du Colombier 		mouse = emouse();
16707dd7cddfSDavid du Colombier     Continue:;
16717dd7cddfSDavid du Colombier 	}
16727dd7cddfSDavid du Colombier 	buttons(Up);
16737dd7cddfSDavid du Colombier 	esetcursor(0);
16747dd7cddfSDavid du Colombier }
16757dd7cddfSDavid du Colombier 
16767dd7cddfSDavid du Colombier void
tclose1(Thing * t)16773e12c5d1SDavid du Colombier tclose1(Thing *t)
16783e12c5d1SDavid du Colombier {
16793e12c5d1SDavid du Colombier 	Thing *nt;
16803e12c5d1SDavid du Colombier 
16813e12c5d1SDavid du Colombier 	if(t == thing)
16823e12c5d1SDavid du Colombier 		thing = t->next;
16833e12c5d1SDavid du Colombier 	else{
16843e12c5d1SDavid du Colombier 		for(nt=thing; nt->next!=t; nt=nt->next)
16853e12c5d1SDavid du Colombier 			;
16863e12c5d1SDavid du Colombier 		nt->next = t->next;
16873e12c5d1SDavid du Colombier 	}
16883e12c5d1SDavid du Colombier 	do
16893e12c5d1SDavid du Colombier 		for(nt=thing; nt; nt=nt->next)
16903e12c5d1SDavid du Colombier 			if(nt->parent == t){
16913e12c5d1SDavid du Colombier 				tclose1(nt);
16923e12c5d1SDavid du Colombier 				break;
16933e12c5d1SDavid du Colombier 			}
16943e12c5d1SDavid du Colombier 	while(nt);
16953e12c5d1SDavid du Colombier 	if(t->s)
16967dd7cddfSDavid du Colombier 		freesubfont(t->s);
16977dd7cddfSDavid du Colombier 	else
16987dd7cddfSDavid du Colombier 		freeimage(t->b);
16993e12c5d1SDavid du Colombier 	free(t->name);
17003e12c5d1SDavid du Colombier 	free(t);
17013e12c5d1SDavid du Colombier }
17023e12c5d1SDavid du Colombier 
17033e12c5d1SDavid du Colombier void
tclose(Thing * t)17043e12c5d1SDavid du Colombier tclose(Thing *t)
17053e12c5d1SDavid du Colombier {
17063e12c5d1SDavid du Colombier 	Thing *ct;
17073e12c5d1SDavid du Colombier 
17083e12c5d1SDavid du Colombier 	if(t->mod){
17093e12c5d1SDavid du Colombier 		mesg("%s modified", t->name);
17103e12c5d1SDavid du Colombier 		t->mod = 0;
17113e12c5d1SDavid du Colombier 		return;
17123e12c5d1SDavid du Colombier 	}
17133e12c5d1SDavid du Colombier 	/* fiddle to save redrawing unmoved things */
17143e12c5d1SDavid du Colombier 	if(t == thing)
17153e12c5d1SDavid du Colombier 		ct = 0;
17163e12c5d1SDavid du Colombier 	else
17173e12c5d1SDavid du Colombier 		for(ct=thing; ct; ct=ct->next)
17183e12c5d1SDavid du Colombier 			if(ct->next==t || ct->next->parent==t)
17193e12c5d1SDavid du Colombier 				break;
17203e12c5d1SDavid du Colombier 	tclose1(t);
17213e12c5d1SDavid du Colombier 	if(ct)
17223e12c5d1SDavid du Colombier 		ct = ct->next;
17233e12c5d1SDavid du Colombier 	else
17243e12c5d1SDavid du Colombier 		ct = thing;
17253e12c5d1SDavid du Colombier 	redraw(ct);
17263e12c5d1SDavid du Colombier }
17273e12c5d1SDavid du Colombier 
17283e12c5d1SDavid du Colombier void
tread(Thing * t)17293e12c5d1SDavid du Colombier tread(Thing *t)
17303e12c5d1SDavid du Colombier {
17313e12c5d1SDavid du Colombier 	Thing *nt, *new;
17323e12c5d1SDavid du Colombier 	Fontchar *i;
17333e12c5d1SDavid du Colombier 	Rectangle r;
17343e12c5d1SDavid du Colombier 	int nclosed;
17353e12c5d1SDavid du Colombier 
17363e12c5d1SDavid du Colombier 	if(t->parent)
17373e12c5d1SDavid du Colombier 		t = t->parent;
17383e12c5d1SDavid du Colombier 	new = tget(t->name);
17393e12c5d1SDavid du Colombier 	if(new == 0)
17403e12c5d1SDavid du Colombier 		return;
17413e12c5d1SDavid du Colombier 	nclosed = 0;
17423e12c5d1SDavid du Colombier     again:
17433e12c5d1SDavid du Colombier 	for(nt=thing; nt; nt=nt->next)
17443e12c5d1SDavid du Colombier 		if(nt->parent == t){
17453e12c5d1SDavid du Colombier 			if(!rectinrect(nt->b->r, new->b->r)
17467dd7cddfSDavid du Colombier 			|| new->b->depth!=nt->b->depth){
17473e12c5d1SDavid du Colombier     closeit:
17483e12c5d1SDavid du Colombier 				nclosed++;
17493e12c5d1SDavid du Colombier 				nt->parent = 0;
17503e12c5d1SDavid du Colombier 				tclose1(nt);
17513e12c5d1SDavid du Colombier 				goto again;
17523e12c5d1SDavid du Colombier 			}
17533e12c5d1SDavid du Colombier 			if((t->s==0) != (new->s==0))
17543e12c5d1SDavid du Colombier 				goto closeit;
17553e12c5d1SDavid du Colombier 			if((t->face==0) != (new->face==0))
17563e12c5d1SDavid du Colombier 				goto closeit;
17573e12c5d1SDavid du Colombier 			if(t->s){	/* check same char */
17583e12c5d1SDavid du Colombier 				if(nt->c >= new->s->n)
17593e12c5d1SDavid du Colombier 					goto closeit;
17603e12c5d1SDavid du Colombier 				i = &new->s->info[nt->c];
17613e12c5d1SDavid du Colombier 				r.min.x = i[0].x;
17623e12c5d1SDavid du Colombier 				r.max.x = i[1].x;
17633e12c5d1SDavid du Colombier 				r.min.y = new->b->r.min.y;
17643e12c5d1SDavid du Colombier 				r.max.y = new->b->r.max.y;
17653e12c5d1SDavid du Colombier 				if(!eqrect(r, nt->b->r))
17663e12c5d1SDavid du Colombier 					goto closeit;
17673e12c5d1SDavid du Colombier 			}
17683e12c5d1SDavid du Colombier 			nt->parent = new;
17697dd7cddfSDavid du Colombier 			draw(nt->b, nt->b->r, new->b, nil, nt->b->r.min);
17703e12c5d1SDavid du Colombier 		}
17713e12c5d1SDavid du Colombier 	new->next = t->next;
17723e12c5d1SDavid du Colombier 	if(t == thing)
17733e12c5d1SDavid du Colombier 		thing = new;
17743e12c5d1SDavid du Colombier 	else{
17753e12c5d1SDavid du Colombier 		for(nt=thing; nt->next!=t; nt=nt->next)
17763e12c5d1SDavid du Colombier 			;
17773e12c5d1SDavid du Colombier 		nt->next = new;
17783e12c5d1SDavid du Colombier 	}
17793e12c5d1SDavid du Colombier 	if(t->s)
17807dd7cddfSDavid du Colombier 		freesubfont(t->s);
17817dd7cddfSDavid du Colombier 	else
17827dd7cddfSDavid du Colombier 		freeimage(t->b);
17833e12c5d1SDavid du Colombier 	free(t->name);
17843e12c5d1SDavid du Colombier 	free(t);
17853e12c5d1SDavid du Colombier 	for(nt=thing; nt; nt=nt->next)
17863e12c5d1SDavid du Colombier 		if(nt==new || nt->parent==new)
17873e12c5d1SDavid du Colombier 			if(nclosed == 0)
17887dd7cddfSDavid du Colombier 				drawthing(nt, 0);	/* can draw in place */
17893e12c5d1SDavid du Colombier 			else{
17903e12c5d1SDavid du Colombier 				redraw(nt);	/* must redraw all below */
17913e12c5d1SDavid du Colombier 				break;
17923e12c5d1SDavid du Colombier 			}
17933e12c5d1SDavid du Colombier }
17943e12c5d1SDavid du Colombier 
17953e12c5d1SDavid du Colombier void
tchar(Thing * t)17963e12c5d1SDavid du Colombier tchar(Thing *t)
17973e12c5d1SDavid du Colombier {
1798219b2ee8SDavid du Colombier 	char buf[256], *p;
17993e12c5d1SDavid du Colombier 	Rune r;
1800219b2ee8SDavid du Colombier 	ulong c, d;
18013e12c5d1SDavid du Colombier 
18023e12c5d1SDavid du Colombier 	if(t->s == 0){
18037dd7cddfSDavid du Colombier 		t = t->parent;
18047dd7cddfSDavid du Colombier 		if(t==0 || t->s==0){
18053e12c5d1SDavid du Colombier 			mesg("not a subfont");
18063e12c5d1SDavid du Colombier 			return;
18073e12c5d1SDavid du Colombier 		}
18087dd7cddfSDavid du Colombier 	}
1809219b2ee8SDavid du Colombier 	if(type(buf, "char (hex or character or hex-hex)") == 0)
18103e12c5d1SDavid du Colombier 		return;
18113e12c5d1SDavid du Colombier 	if(utflen(buf) == 1){
18123e12c5d1SDavid du Colombier 		chartorune(&r, buf);
18133e12c5d1SDavid du Colombier 		c = r;
1814219b2ee8SDavid du Colombier 		d = r;
18153e12c5d1SDavid du Colombier 	}else{
18163e12c5d1SDavid du Colombier 		if(!strchr(hex, buf[0])){
18173e12c5d1SDavid du Colombier 			mesg("illegal hex character");
18183e12c5d1SDavid du Colombier 			return;
18193e12c5d1SDavid du Colombier 		}
18203e12c5d1SDavid du Colombier 		c = strtoul(buf, 0, 16);
1821219b2ee8SDavid du Colombier 		d = c;
1822219b2ee8SDavid du Colombier 		p = utfrune(buf, '-');
1823219b2ee8SDavid du Colombier 		if(p){
1824219b2ee8SDavid du Colombier 			d = strtoul(p+1, 0, 16);
1825219b2ee8SDavid du Colombier 			if(d < c){
1826219b2ee8SDavid du Colombier 				mesg("invalid range");
1827219b2ee8SDavid du Colombier 				return;
1828219b2ee8SDavid du Colombier 			}
1829219b2ee8SDavid du Colombier 		}
18303e12c5d1SDavid du Colombier 	}
18313e12c5d1SDavid du Colombier 	c -= t->off;
1832219b2ee8SDavid du Colombier 	d -= t->off;
1833219b2ee8SDavid du Colombier 	while(c <= d){
1834c93608ccSDavid du Colombier 		if(c>=t->s->n){
18353e12c5d1SDavid du Colombier 			mesg("0x%lux not in font %s", c+t->off, t->name);
18363e12c5d1SDavid du Colombier 			return;
18373e12c5d1SDavid du Colombier 		}
18383e12c5d1SDavid du Colombier 		openedit(t, Pt(0, 0), c);
1839219b2ee8SDavid du Colombier 		c++;
1840219b2ee8SDavid du Colombier 	}
18413e12c5d1SDavid du Colombier }
18423e12c5d1SDavid du Colombier 
18433e12c5d1SDavid du Colombier void
apply(void (* f)(Thing *))18443e12c5d1SDavid du Colombier apply(void (*f)(Thing*))
18453e12c5d1SDavid du Colombier {
18463e12c5d1SDavid du Colombier 	Thing *t;
18473e12c5d1SDavid du Colombier 
18487dd7cddfSDavid du Colombier 	esetcursor(&sight);
18493e12c5d1SDavid du Colombier 	buttons(Down);
18503e12c5d1SDavid du Colombier 	if(mouse.buttons == 4)
18513e12c5d1SDavid du Colombier 		for(t=thing; t; t=t->next)
18523e12c5d1SDavid du Colombier 			if(ptinrect(mouse.xy, t->er)){
18533e12c5d1SDavid du Colombier 				buttons(Up);
18543e12c5d1SDavid du Colombier 				f(t);
18553e12c5d1SDavid du Colombier 				break;
18563e12c5d1SDavid du Colombier 			}
18573e12c5d1SDavid du Colombier 	buttons(Up);
18587dd7cddfSDavid du Colombier 	esetcursor(0);
18597dd7cddfSDavid du Colombier }
18607dd7cddfSDavid du Colombier 
18617dd7cddfSDavid du Colombier int
complement(Image * t)18627dd7cddfSDavid du Colombier complement(Image *t)
18637dd7cddfSDavid du Colombier {
18647dd7cddfSDavid du Colombier 	int i, n;
18657dd7cddfSDavid du Colombier 	uchar *buf;
18667dd7cddfSDavid du Colombier 
18677dd7cddfSDavid du Colombier 	n = Dy(t->r)*bytesperline(t->r, t->depth);
18687dd7cddfSDavid du Colombier 	buf = malloc(n);
18697dd7cddfSDavid du Colombier 	if(buf == 0)
18707dd7cddfSDavid du Colombier 		return 0;
18717dd7cddfSDavid du Colombier 	unloadimage(t, t->r, buf, n);
18727dd7cddfSDavid du Colombier 	for(i=0; i<n; i++)
18737dd7cddfSDavid du Colombier 		buf[i] = ~buf[i];
18747dd7cddfSDavid du Colombier 	loadimage(t, t->r, buf, n);
18757dd7cddfSDavid du Colombier 	free(buf);
18767dd7cddfSDavid du Colombier 	return 1;
18773e12c5d1SDavid du Colombier }
18783e12c5d1SDavid du Colombier 
18793e12c5d1SDavid du Colombier void
copy(void)18803e12c5d1SDavid du Colombier copy(void)
18813e12c5d1SDavid du Colombier {
18823e12c5d1SDavid du Colombier 	Thing *st, *dt, *nt;
18833e12c5d1SDavid du Colombier 	Rectangle sr, dr, fr;
18847dd7cddfSDavid du Colombier 	Image *tmp;
18853e12c5d1SDavid du Colombier 	Point p1, p2;
18863e12c5d1SDavid du Colombier 	int but, up;
18873e12c5d1SDavid du Colombier 
18887dd7cddfSDavid du Colombier 	if(!sweep(3, &sr))
18893e12c5d1SDavid du Colombier 		return;
18903e12c5d1SDavid du Colombier 	for(st=thing; st; st=st->next)
18913e12c5d1SDavid du Colombier 		if(rectXrect(sr, st->r))
18923e12c5d1SDavid du Colombier 			break;
18933e12c5d1SDavid du Colombier 	if(st == 0)
18943e12c5d1SDavid du Colombier 		return;
18953e12c5d1SDavid du Colombier 	/* click gives full rectangle */
18963e12c5d1SDavid du Colombier 	if(Dx(sr)<4 && Dy(sr)<4)
18973e12c5d1SDavid du Colombier 		sr = st->r;
18983e12c5d1SDavid du Colombier 	rectclip(&sr, st->r);
18993e12c5d1SDavid du Colombier 	p1 = realpt(st, sr.min);
19003e12c5d1SDavid du Colombier 	p2 = realpt(st, Pt(sr.min.x, sr.max.y));
190180ee5cbfSDavid du Colombier 	up = 0;
19023e12c5d1SDavid du Colombier 	if(p1.x != p2.x){	/* swept across a fold */
19033e12c5d1SDavid du Colombier    onafold:
19043e12c5d1SDavid du Colombier 		mesg("sweep spans a fold");
190580ee5cbfSDavid du Colombier 		goto Return;
19063e12c5d1SDavid du Colombier 	}
19073e12c5d1SDavid du Colombier 	p2 = realpt(st, sr.max);
19083e12c5d1SDavid du Colombier 	sr.min = p1;
19093e12c5d1SDavid du Colombier 	sr.max = p2;
19103e12c5d1SDavid du Colombier 	fr.min = screenpt(st, sr.min);
19113e12c5d1SDavid du Colombier 	fr.max = screenpt(st, sr.max);
19127dd7cddfSDavid du Colombier 	p1 = subpt(p2, p1);	/* diagonal */
19137dd7cddfSDavid du Colombier 	if(p1.x==0 || p1.y==0)
19143e12c5d1SDavid du Colombier 		return;
19157dd7cddfSDavid du Colombier 	border(screen, fr, -1, values[Blue], ZP);
19167dd7cddfSDavid du Colombier 	esetcursor(&box);
19173e12c5d1SDavid du Colombier 	for(; mouse.buttons==0; mouse=emouse()){
19183e12c5d1SDavid du Colombier 		for(dt=thing; dt; dt=dt->next)
19193e12c5d1SDavid du Colombier 			if(ptinrect(mouse.xy, dt->er))
19203e12c5d1SDavid du Colombier 				break;
19213e12c5d1SDavid du Colombier 		if(up)
19227dd7cddfSDavid du Colombier 			edrawgetrect(insetrect(dr, -Borderwidth), 0);
19233e12c5d1SDavid du Colombier 		up = 0;
19243e12c5d1SDavid du Colombier 		if(dt == 0)
19253e12c5d1SDavid du Colombier 			continue;
19263e12c5d1SDavid du Colombier 		dr.max = screenpt(dt, realpt(dt, mouse.xy));
19277dd7cddfSDavid du Colombier 		dr.min = subpt(dr.max, mulpt(p1, dt->mag));
19283e12c5d1SDavid du Colombier 		if(!rectXrect(dr, dt->r))
19293e12c5d1SDavid du Colombier 			continue;
19307dd7cddfSDavid du Colombier 		edrawgetrect(insetrect(dr, -Borderwidth), 1);
19313e12c5d1SDavid du Colombier 		up = 1;
19323e12c5d1SDavid du Colombier 	}
19333e12c5d1SDavid du Colombier 	/* if up==1, we had a hit */
19347dd7cddfSDavid du Colombier 	esetcursor(0);
19353e12c5d1SDavid du Colombier 	if(up)
19367dd7cddfSDavid du Colombier 		edrawgetrect(insetrect(dr, -Borderwidth), 0);
19373e12c5d1SDavid du Colombier 	but = mouse.buttons;
19383e12c5d1SDavid du Colombier 	buttons(Up);
19393e12c5d1SDavid du Colombier 	if(!up || but!=4)
19407dd7cddfSDavid du Colombier 		goto Return;
19413e12c5d1SDavid du Colombier 	dt = 0;
19423e12c5d1SDavid du Colombier 	for(nt=thing; nt; nt=nt->next)
19433e12c5d1SDavid du Colombier 		if(rectXrect(dr, nt->r)){
19443e12c5d1SDavid du Colombier 			if(dt){
19453e12c5d1SDavid du Colombier 				mesg("ambiguous sweep");
19463e12c5d1SDavid du Colombier 				return;
19473e12c5d1SDavid du Colombier 			}
19483e12c5d1SDavid du Colombier 			dt = nt;
19493e12c5d1SDavid du Colombier 		}
19503e12c5d1SDavid du Colombier 	if(dt == 0)
19517dd7cddfSDavid du Colombier 		goto Return;
19523e12c5d1SDavid du Colombier 	p1 = realpt(dt, dr.min);
19533e12c5d1SDavid du Colombier 	p2 = realpt(dt, Pt(dr.min.x, dr.max.y));
19543e12c5d1SDavid du Colombier 	if(p1.x != p2.x)
19553e12c5d1SDavid du Colombier 		goto onafold;
19563e12c5d1SDavid du Colombier 	p2 = realpt(dt, dr.max);
19573e12c5d1SDavid du Colombier 	dr.min = p1;
19583e12c5d1SDavid du Colombier 	dr.max = p2;
19597dd7cddfSDavid du Colombier 
19607dd7cddfSDavid du Colombier 	if(invert){
19617dd7cddfSDavid du Colombier 		tmp = allocimage(display, dr, dt->b->chan, 0, 255);
19627dd7cddfSDavid du Colombier 		if(tmp == 0){
19637dd7cddfSDavid du Colombier     nomem:
19647dd7cddfSDavid du Colombier 			mesg("can't allocate temporary");
19657dd7cddfSDavid du Colombier 			goto Return;
19667dd7cddfSDavid du Colombier 		}
19677dd7cddfSDavid du Colombier 		draw(tmp, dr, st->b, nil, sr.min);
19687dd7cddfSDavid du Colombier 		if(!complement(tmp))
19697dd7cddfSDavid du Colombier 			goto nomem;
19707dd7cddfSDavid du Colombier 		draw(dt->b, dr, tmp, nil, dr.min);
19717dd7cddfSDavid du Colombier 		freeimage(tmp);
19727dd7cddfSDavid du Colombier 	}else
19737dd7cddfSDavid du Colombier 		draw(dt->b, dr, st->b, nil, sr.min);
19743e12c5d1SDavid du Colombier 	if(dt->parent){
19757dd7cddfSDavid du Colombier 		draw(dt->parent->b, dr, dt->b, nil, dr.min);
19763e12c5d1SDavid du Colombier 		dt = dt->parent;
19773e12c5d1SDavid du Colombier 	}
19787dd7cddfSDavid du Colombier 	drawthing(dt, 0);
19793e12c5d1SDavid du Colombier 	for(nt=thing; nt; nt=nt->next)
19803e12c5d1SDavid du Colombier 		if(nt->parent==dt && rectXrect(dr, nt->b->r)){
19817dd7cddfSDavid du Colombier 			draw(nt->b, dr, dt->b, nil, dr.min);
19827dd7cddfSDavid du Colombier 			drawthing(nt, 0);
19833e12c5d1SDavid du Colombier 		}
19843e12c5d1SDavid du Colombier 	ckinfo(dt, dr);
19853e12c5d1SDavid du Colombier 	dt->mod = 1;
19867dd7cddfSDavid du Colombier 
19877dd7cddfSDavid du Colombier Return:
19887dd7cddfSDavid du Colombier 	/* clear blue box */
19897dd7cddfSDavid du Colombier 	drawthing(st, 0);
19903e12c5d1SDavid du Colombier }
19913e12c5d1SDavid du Colombier 
19923e12c5d1SDavid du Colombier void
menu(void)19933e12c5d1SDavid du Colombier menu(void)
19943e12c5d1SDavid du Colombier {
19953e12c5d1SDavid du Colombier 	Thing *t;
19963e12c5d1SDavid du Colombier 	char *mod;
19973e12c5d1SDavid du Colombier 	int sel;
19983e12c5d1SDavid du Colombier 	char buf[256];
19993e12c5d1SDavid du Colombier 
20007dd7cddfSDavid du Colombier 	sel = emenuhit(3, &mouse, &menu3);
20013e12c5d1SDavid du Colombier 	switch(sel){
20023e12c5d1SDavid du Colombier 	case Mopen:
20033e12c5d1SDavid du Colombier 		if(type(buf, "file")){
20043e12c5d1SDavid du Colombier 			t = tget(buf);
20053e12c5d1SDavid du Colombier 			if(t)
20067dd7cddfSDavid du Colombier 				drawthing(t, 1);
20073e12c5d1SDavid du Colombier 		}
20083e12c5d1SDavid du Colombier 		break;
20093e12c5d1SDavid du Colombier 	case Mwrite:
20103e12c5d1SDavid du Colombier 		apply(twrite);
20113e12c5d1SDavid du Colombier 		break;
20123e12c5d1SDavid du Colombier 	case Mread:
20133e12c5d1SDavid du Colombier 		apply(tread);
20143e12c5d1SDavid du Colombier 		break;
20153e12c5d1SDavid du Colombier 	case Mchar:
20163e12c5d1SDavid du Colombier 		apply(tchar);
20173e12c5d1SDavid du Colombier 		break;
20183e12c5d1SDavid du Colombier 	case Mcopy:
20193e12c5d1SDavid du Colombier 		copy();
20203e12c5d1SDavid du Colombier 		break;
20217dd7cddfSDavid du Colombier 	case Mpixels:
20227dd7cddfSDavid du Colombier 		tpixels();
20237dd7cddfSDavid du Colombier 		break;
20243e12c5d1SDavid du Colombier 	case Mclose:
20253e12c5d1SDavid du Colombier 		apply(tclose);
20263e12c5d1SDavid du Colombier 		break;
20273e12c5d1SDavid du Colombier 	case Mexit:
20283e12c5d1SDavid du Colombier 		mod = 0;
20293e12c5d1SDavid du Colombier 		for(t=thing; t; t=t->next)
20303e12c5d1SDavid du Colombier 			if(t->mod){
20313e12c5d1SDavid du Colombier 				mod = t->name;
20323e12c5d1SDavid du Colombier 				t->mod = 0;
20333e12c5d1SDavid du Colombier 			}
20343e12c5d1SDavid du Colombier 		if(mod){
20353e12c5d1SDavid du Colombier 			mesg("%s modified", mod);
20363e12c5d1SDavid du Colombier 			break;
20373e12c5d1SDavid du Colombier 		}
20387dd7cddfSDavid du Colombier 		esetcursor(&skull);
20393e12c5d1SDavid du Colombier 		buttons(Down);
20403e12c5d1SDavid du Colombier 		if(mouse.buttons == 4){
20413e12c5d1SDavid du Colombier 			buttons(Up);
20423e12c5d1SDavid du Colombier 			exits(0);
20433e12c5d1SDavid du Colombier 		}
20443e12c5d1SDavid du Colombier 		buttons(Up);
20457dd7cddfSDavid du Colombier 		esetcursor(0);
20463e12c5d1SDavid du Colombier 		break;
20473e12c5d1SDavid du Colombier 	}
20483e12c5d1SDavid du Colombier }
2049