Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}