314 lines · 5.9 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <draw.h>#include <bio.h>#include <thread.h>#include <mouse.h>#include <keyboard.h> enum {	STACK 	= 8*1024, 	Dot	= 2,	/* height of dot */	Lx	= 4,	/* x offset */	Ly	= 4,	/* y offset */	Bw	= 2,	/* border width */}; Image *neutral;Image *light;Image *dark;Image *txtcolor; char *title = "histogram";Rectangle hrect;Point maxvloc;double *data;double vmax = 100, scale = 1.0;uint nval;int dontdie = 0, col = 1; int colors[][3] = {	{ 0xFFAAAAFF,	0xFFAAAAFF,	0xBB5D5DFF },		/* Peach */	{ DPalebluegreen, DPalegreygreen, DPurpleblue },	/* Aqua */	{ DPaleyellow,	DDarkyellow,	DYellowgreen },		/* Yellow */	{ DPalegreen,	DMedgreen,	DDarkgreen },		/* Green */	{ 0x00AAFFFF,	0x00AAFFFF,	0x0088CCFF },		/* Blue */	{ 0xEEEEEEFF,	0xCCCCCCFF,	0x888888F },		/* Grey */}; voidinitcolor(int i){	neutral = allocimagemix(display, colors[i][0], DWhite);	light = allocimage(display, Rect(0,0,1,1), CMAP8, 1, colors[i][1]);	dark  = allocimage(display, Rect(0,0,1,1), CMAP8, 1, colors[i][2]);	txtcolor = display->black;} void*erealloc(void *v, ulong sz){	v = realloc(v, sz);	if(v == nil){		sysfatal("realloc: %r");		threadexitsall("memory");	}	return v;} Pointdatapoint(int x, double v){	Point p;	double y; 	p.x = x;	y = (v*scale) / vmax;	p.y = hrect.max.y - Dy(hrect)*y - Dot;	if(p.y < hrect.min.y)		p.y = hrect.min.y;	if(p.y > hrect.max.y - Dot)		p.y = hrect.max.y - Dot;	return p;} voiddrawdatum(int x, double prev, double v){	Point p, q; 	p = datapoint(x, v);	q = datapoint(x, prev);	if(p.y < q.y){		draw(screen, Rect(p.x, hrect.min.y, p.x+1, p.y), neutral,			nil, ZP);		draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), dark, nil, ZP);		draw(screen, Rect(p.x, q.y+Dot, p.x+1, hrect.max.y), light,			nil, ZP);	}else{		draw(screen, Rect(p.x, hrect.min.y, p.x+1, q.y), neutral,			nil, ZP);		draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), dark, nil, ZP);		draw(screen, Rect(p.x, p.y+Dot, p.x+1, hrect.max.y), light,			nil, ZP);	} } voidupdatehistogram(double v){	char buf[32]; 	draw(screen, hrect, screen, nil, Pt(hrect.min.x+1, hrect.min.y));	if(v * scale > vmax)		v = vmax / scale;	drawdatum(hrect.max.x-1, data[0], v);	memmove(&data[1], &data[0], (nval-1) * sizeof data[0]);	data[0] = v;	snprint(buf, sizeof buf, "%0.9f", v);	stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf,		neutral, ZP);	flushimage(display, 1);} voidredrawhistogram(int new){	Point p, q;	Rectangle r;	uint onval = nval;	int i;	char buf[32]; 	if(new && getwindow(display, Refnone) < 0)		sysfatal("getwindow: %r"); 	r = screen->r;	draw(screen, r, neutral, nil, ZP);	p = string(screen, addpt(r.min, Pt(Lx, Ly)), txtcolor, ZP,		display->defaultfont, title); 	p.x = r.min.x + Lx;	p.y += display->defaultfont->height + Ly; 	q = subpt(r.max, Pt(Lx, Ly));	hrect = Rpt(p, q); 	maxvloc = Pt(r.max.x - Lx - stringwidth(display->defaultfont,		"999999999"), r.min.y + Ly); 	nval = abs(Dx(hrect));	if(nval != onval){		data = erealloc(data, nval * sizeof data[0]);		if(nval > onval)			memset(data+onval, 0, (nval - onval) * sizeof data[0]);	} 	border(screen, hrect, -Bw, dark, ZP);	snprint(buf, sizeof buf, "%0.9f", data[0]);	stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf,		neutral, ZP);	draw(screen, hrect, neutral, nil, ZP);	for(i = 1; i < nval - 1; i++)		drawdatum(hrect.max.x - i, data[i-1], data[i]);	drawdatum(hrect.min.x, data[i], data[i]);	flushimage(display, 1);} voidreader(void *arg){	int fd;	double v;	char *p, *f[2];	uchar buf[512];	Biobufhdr b;	Channel *c = arg; 	threadsetname("reader");	fd = dup(0, -1);	Binits(&b, fd, OREAD, buf, sizeof buf); 	while((p = Brdline(&b, '\n')) != nil) {		p[Blinelen(&b) - 1] = '\0';		if(tokenize(p, f, 1) != 1)			continue;		v = strtod(f[0], 0);		send(c, &v);	}	if(!dontdie)		threadexitsall(nil);}  voidhistogram(char *rect){	int rm;	double dm;	Channel *dc;	Keyboardctl *kc;	Mouse mm;	Mousectl *mc;	Rune km;	Alt a[] = {		/* c	v	op */		{nil,	&dm,	CHANRCV},	/* data from stdin */		{nil,	&mm,	CHANRCV},	/* mouse message */		{nil,	&km,	CHANRCV},	/* keyboard runes */		{nil,	&rm,	CHANRCV},	/* resize event */		{nil,	nil,	CHANEND},	};	static char *mitems[] = {		"exit",		nil	};	static Menu menu = {		mitems,		nil,		-1	}; 	memset(&mm, 0, sizeof mm);	memset(&km, 0, sizeof km);	dm = rm = 0; 	if(newwindow(rect) < 0)		sysfatal("newwindow: %r");	if(initdraw(nil, nil, "histogram") < 0)		sysfatal("initdraw: %r"); 	initcolor(col); 	mc = initmouse(nil, screen);	if(!mc)		sysfatal("initmouse: %r");	kc = initkeyboard(nil);	if(!kc)		sysfatal("initkeyboard: %r"); 	dc = chancreate(sizeof dm, 10);	if(!dc)		sysfatal("chancreate: %r"); 	a[0].c = dc;	a[1].c = mc->c;	a[2].c = kc->c;	a[3].c = mc->resizec; 	proccreate(reader, a[0].c, STACK + sizeof(Biobuf)); 	redrawhistogram(0);	for(;;)		switch(alt(a)){		case 0:			updatehistogram(dm);			break;		case 1:			if(mm.buttons & 4 && menuhit(3, mc, &menu, nil) == 0)				goto done;			break;		case 2:			if(km == 0x7F)				goto done;			break;		case 3:			redrawhistogram(1);			break;		default:			sysfatal("shouldn't happen");		}done:	closekeyboard(kc);	closemouse(mc);	chanfree(a[0].c);	threadexitsall(nil);} voidusage(void){	fprint(2, "usage: histogram [-h] [-c index] [-r minx,miny,maxx,maxy] "		"[-s scale] [-t title] [-v maxv]\n");	exits("usage");} voidthreadmain(int argc, char **argv){	char *p, *q; 	p = "-r 0,0,400,150"; 	ARGBEGIN{	case 'v':		vmax = strtod(EARGF(usage()), 0);		break;	case 'r':		p = smprint("-r %s", EARGF(usage()));		break;	case 's':		scale = strtod(EARGF(usage()), 0);		if(scale <= 0)			usage();		break;	case 'h':		dontdie = 1;		break;	case 't':		title = EARGF(usage());		break;	case 'c':		col = atoi(EARGF(usage())) % nelem(colors);		break;	default:		usage();	}ARGEND; 	while((q = strchr(p, ',')) != nil)		*q = ' '; 	histogram(p);}