]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/histogram.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / cmd / histogram.c
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 }