#include #include #include #include #include #include #include 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, vmax = 100; double scale = 1.0; uint nval; int dontdie = 0; int 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 */ }; void initcolor(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; } Point datapoint(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; } void drawdatum(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); } } void updatehistogram(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; sprint(buf, "%0.9f", v); stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf, neutral, ZP); flushimage(display, 1); } void redrawhistogram(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); sprint(buf, "%0.9f", data[0]); stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf, neutral, ZP); draw(screen, hrect, neutral, nil, ZP); for(i=1; ic; 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); } void usage(void) { fprint(2, "usage: aux/histogram [-h] [-c color index[-v maxv] [-s scale] [-r minx,miny,maxx,maxy] [-t 'title']\n"); exits("usage"); } void threadmain(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", ARGF()); 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())); col %= sizeof(colors)/sizeof(colors[0]); break; default: usage(); }ARGEND; while(q = strchr(p, ',')) *q = ' '; histogram(p); }