1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <bio.h> 5 #include <thread.h> 6 #include <mouse.h> 7 #include <keyboard.h> 8 9 enum { 10 STACK = 8*1024, 11 12 Dot = 2, /* height of dot */ 13 Lx = 4, /* x offset */ 14 Ly = 4, /* y offset */ 15 Bw = 2, /* border width */ 16 }; 17 18 Image *neutral; 19 Image *light; 20 Image *dark; 21 Image *txtcolor; 22 23 char *title = "histogram"; 24 Rectangle hrect; 25 Point maxvloc; 26 double *data; 27 double vmax = 100, scale = 1.0; 28 uint nval; 29 int dontdie = 0, col = 1; 30 31 int colors[][3] = { 32 { 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF }, /* Peach */ 33 { DPalebluegreen, DPalegreygreen, DPurpleblue }, /* Aqua */ 34 { DPaleyellow, DDarkyellow, DYellowgreen }, /* Yellow */ 35 { DPalegreen, DMedgreen, DDarkgreen }, /* Green */ 36 { 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF }, /* Blue */ 37 { 0xEEEEEEFF, 0xCCCCCCFF, 0x888888F }, /* Grey */ 38 }; 39 40 void 41 initcolor(int i) 42 { 43 neutral = allocimagemix(display, colors[i][0], DWhite); 44 light = allocimage(display, Rect(0,0,1,1), CMAP8, 1, colors[i][1]); 45 dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, colors[i][2]); 46 txtcolor = display->black; 47 } 48 49 void* 50 erealloc(void *v, ulong sz) 51 { 52 v = realloc(v, sz); 53 if(v == nil){ 54 sysfatal("realloc: %r"); 55 threadexitsall("memory"); 56 } 57 return v; 58 } 59 60 Point 61 datapoint(int x, double v) 62 { 63 Point p; 64 double y; 65 66 p.x = x; 67 y = (v*scale) / vmax; 68 p.y = hrect.max.y - Dy(hrect)*y - Dot; 69 if(p.y < hrect.min.y) 70 p.y = hrect.min.y; 71 if(p.y > hrect.max.y - Dot) 72 p.y = hrect.max.y - Dot; 73 return p; 74 } 75 76 void 77 drawdatum(int x, double prev, double v) 78 { 79 Point p, q; 80 81 p = datapoint(x, v); 82 q = datapoint(x, prev); 83 if(p.y < q.y){ 84 draw(screen, Rect(p.x, hrect.min.y, p.x+1, p.y), neutral, 85 nil, ZP); 86 draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), dark, nil, ZP); 87 draw(screen, Rect(p.x, q.y+Dot, p.x+1, hrect.max.y), light, 88 nil, ZP); 89 }else{ 90 draw(screen, Rect(p.x, hrect.min.y, p.x+1, q.y), neutral, 91 nil, ZP); 92 draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), dark, nil, ZP); 93 draw(screen, Rect(p.x, p.y+Dot, p.x+1, hrect.max.y), light, 94 nil, ZP); 95 } 96 97 } 98 99 void 100 updatehistogram(double v) 101 { 102 char buf[32]; 103 104 draw(screen, hrect, screen, nil, Pt(hrect.min.x+1, hrect.min.y)); 105 if(v * scale > vmax) 106 v = vmax / scale; 107 drawdatum(hrect.max.x-1, data[0], v); 108 memmove(&data[1], &data[0], (nval-1) * sizeof data[0]); 109 data[0] = v; 110 snprint(buf, sizeof buf, "%0.9f", v); 111 stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf, 112 neutral, ZP); 113 flushimage(display, 1); 114 } 115 116 void 117 redrawhistogram(int new) 118 { 119 Point p, q; 120 Rectangle r; 121 uint onval = nval; 122 int i; 123 char buf[32]; 124 125 if(new && getwindow(display, Refnone) < 0) 126 sysfatal("getwindow: %r"); 127 128 r = screen->r; 129 draw(screen, r, neutral, nil, ZP); 130 p = string(screen, addpt(r.min, Pt(Lx, Ly)), txtcolor, ZP, 131 display->defaultfont, title); 132 133 p.x = r.min.x + Lx; 134 p.y += display->defaultfont->height + Ly; 135 136 q = subpt(r.max, Pt(Lx, Ly)); 137 hrect = Rpt(p, q); 138 139 maxvloc = Pt(r.max.x - Lx - stringwidth(display->defaultfont, 140 "999999999"), r.min.y + Ly); 141 142 nval = abs(Dx(hrect)); 143 if(nval != onval){ 144 data = erealloc(data, nval * sizeof data[0]); 145 if(nval > onval) 146 memset(data+onval, 0, (nval - onval) * sizeof data[0]); 147 } 148 149 border(screen, hrect, -Bw, dark, ZP); 150 snprint(buf, sizeof buf, "%0.9f", data[0]); 151 stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf, 152 neutral, ZP); 153 draw(screen, hrect, neutral, nil, ZP); 154 for(i = 1; i < nval - 1; i++) 155 drawdatum(hrect.max.x - i, data[i-1], data[i]); 156 drawdatum(hrect.min.x, data[i], data[i]); 157 flushimage(display, 1); 158 } 159 160 void 161 reader(void *arg) 162 { 163 int fd; 164 double v; 165 char *p, *f[2]; 166 uchar buf[512]; 167 Biobufhdr b; 168 Channel *c = arg; 169 170 threadsetname("reader"); 171 fd = dup(0, -1); 172 Binits(&b, fd, OREAD, buf, sizeof buf); 173 174 while((p = Brdline(&b, '\n')) != nil) { 175 p[Blinelen(&b) - 1] = '\0'; 176 if(tokenize(p, f, 1) != 1) 177 continue; 178 v = strtod(f[0], 0); 179 send(c, &v); 180 } 181 if(!dontdie) 182 threadexitsall(nil); 183 } 184 185 186 void 187 histogram(char *rect) 188 { 189 int rm; 190 double dm; 191 Channel *dc; 192 Keyboardctl *kc; 193 Mouse mm; 194 Mousectl *mc; 195 Rune km; 196 Alt a[] = { 197 /* c v op */ 198 {nil, &dm, CHANRCV}, /* data from stdin */ 199 {nil, &mm, CHANRCV}, /* mouse message */ 200 {nil, &km, CHANRCV}, /* keyboard runes */ 201 {nil, &rm, CHANRCV}, /* resize event */ 202 {nil, nil, CHANEND}, 203 }; 204 static char *mitems[] = { 205 "exit", 206 nil 207 }; 208 static Menu menu = { 209 mitems, 210 nil, 211 -1 212 }; 213 214 memset(&mm, 0, sizeof mm); 215 memset(&km, 0, sizeof km); 216 dm = rm = 0; 217 218 if(newwindow(rect) < 0) 219 sysfatal("newwindow: %r"); 220 if(initdraw(nil, nil, "histogram") < 0) 221 sysfatal("initdraw: %r"); 222 223 initcolor(col); 224 225 mc = initmouse(nil, screen); 226 if(!mc) 227 sysfatal("initmouse: %r"); 228 kc = initkeyboard(nil); 229 if(!kc) 230 sysfatal("initkeyboard: %r"); 231 232 dc = chancreate(sizeof dm, 10); 233 if(!dc) 234 sysfatal("chancreate: %r"); 235 236 a[0].c = dc; 237 a[1].c = mc->c; 238 a[2].c = kc->c; 239 a[3].c = mc->resizec; 240 241 proccreate(reader, a[0].c, STACK + sizeof(Biobuf)); 242 243 redrawhistogram(0); 244 for(;;) 245 switch(alt(a)){ 246 case 0: 247 updatehistogram(dm); 248 break; 249 case 1: 250 if(mm.buttons & 4 && menuhit(3, mc, &menu, nil) == 0) 251 goto done; 252 break; 253 case 2: 254 if(km == 0x7F) 255 goto done; 256 break; 257 case 3: 258 redrawhistogram(1); 259 break; 260 default: 261 sysfatal("shouldn't happen"); 262 } 263 done: 264 closekeyboard(kc); 265 closemouse(mc); 266 chanfree(a[0].c); 267 threadexitsall(nil); 268 } 269 270 void 271 usage(void) 272 { 273 fprint(2, "usage: histogram [-h] [-c index] [-r minx,miny,maxx,maxy] " 274 "[-s scale] [-t title] [-v maxv]\n"); 275 exits("usage"); 276 } 277 278 void 279 threadmain(int argc, char **argv) 280 { 281 char *p, *q; 282 283 p = "-r 0,0,400,150"; 284 285 ARGBEGIN{ 286 case 'v': 287 vmax = strtod(EARGF(usage()), 0); 288 break; 289 case 'r': 290 p = smprint("-r %s", EARGF(usage())); 291 break; 292 case 's': 293 scale = strtod(EARGF(usage()), 0); 294 if(scale <= 0) 295 usage(); 296 break; 297 case 'h': 298 dontdie = 1; 299 break; 300 case 't': 301 title = EARGF(usage()); 302 break; 303 case 'c': 304 col = atoi(EARGF(usage())) % nelem(colors); 305 break; 306 default: 307 usage(); 308 }ARGEND; 309 310 while((q = strchr(p, ',')) != nil) 311 *q = ' '; 312 313 histogram(p); 314 } 315