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