ref: 8f27ffaf6569d4284b370a25377e6dd86edfa563
dir: /ui/ui.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <thread.h>
enum {
	Dback = 0,
	Dfhigh,
	Dfmed,
	Dflow,
	Dfinv,
	Dbhigh,
	Dbmed,
	Dblow,
	Dbinv,
	Numcolors,
	Knobleft360 = 0<<0,
	Knobtop180 = 1<<0,
	Knobvaluetop = 0<<1,
	Knobvaluebot = 1<<1,
};
#define MIN(a,b) ((a)<=(b)?(a):(b))
#define MAX(a,b) ((a)>=(b)?(a):(b))
static struct {
	char *id;
	u32int color;
}theme[Numcolors] = {
	[Dback]  = {"background", 0x000000},
	[Dfhigh] = {"f_high",     0xffffff},
	[Dfmed]  = {"f_med",      0x777777},
	[Dflow]  = {"f_low",      0x444444},
	[Dfinv]  = {"f_inv",      0x000000},
	[Dbhigh] = {"b_high",     0xdddddd},
	[Dbmed]  = {"b_med",      0x72dec2},
	[Dblow]  = {"b_low",      0x222222},
	[Dbinv]  = {"b_inv",      0xffb545},
};
typedef struct Style Style;
struct Style {
	struct {
		int r;
		int w;
	}knob;
	int margin;
	Font *font;
};
static Style style = {
	.knob = {
		.r = 24,
		.w = 4,
	},
	.margin = 4,
};
static Image *color[Numcolors];
static Rectangle knobs[8][2];
static Rectangle
knob(Rectangle r, char *d, char *vs, float v, int kt)
{
	Point c, t, p0, p1;
	int a, hw, dw, vw;
	dw = stringwidth(style.font, d);
	vw = stringwidth(style.font, vs);
	hw = MAX(style.knob.r, MAX(dw, vw)/2); /* "half width", center of the component */
	r.max = r.min;
	r.max.x += hw*2;
	/* value */
	if (vw > 0 && !(kt&Knobvaluebot)) {
valuebot:
		t.x = r.min.x + hw - vw/2;
		t.y = r.max.y;
		string(screen, t, color[Dfhigh], ZP, style.font, vs);
		r.max.y = t.y + style.font->height + style.margin;
		if (kt & Knobvaluebot)
			return r;
	}
	/* knob */
	a = (kt&Knobtop180) ? 90 : 180;
	v = v*((kt&Knobtop180) ? -180 : -360);
	c.x = r.min.x + Dx(r)/2;
	c.y = r.max.y + style.knob.r;
	fillarc(screen, c, style.knob.r, style.knob.r, color[Dfhigh], ZP, a, v);
	fillellipse(screen, c, style.knob.r-style.knob.w, style.knob.r-style.knob.w, color[Dflow], ZP);
	icossin(a+v, &p0.x, &p0.y);
	p1.x = c.x + p0.x*(style.knob.r-style.knob.w*4/3)/1024;
	p1.y = c.y - p0.y*(style.knob.r-style.knob.w*4/3)/1024;
	p0.x = c.x + p0.x*style.knob.w*3/1024;
	p0.y = c.y - p0.y*style.knob.w*3/1024;
	line(screen, p0, p1, 0, 0, 0, color[Dfhigh], ZP);
	r.max.y += 2*style.knob.r;
	/* description */
	if (dw > 0) {
		t.x = r.min.x + hw - dw/2;
		t.y = r.max.y + style.margin;
		string(screen, t, color[Dfhigh], ZP, style.font, d);
		r.max.y = t.y + style.font->height;
	}
	if (kt & Knobvaluebot) {
		r.max.y += style.margin;
		goto valuebot;
	}
	return r;
}
static void
redraw(void)
{
	float f;
	Rectangle r, t;
	char s[16];
	int i;
	lockdisplay(display);
	r = screen->r;
	draw(screen, r, color[Dback], nil, ZP);
	r.min.x += style.margin;
	r.min.y += style.margin;
	for (i = 0; i < nelem(knobs); i++) {
		f = (i+1)*0.1;
		sprint(s, "%g", f);
		t = knob(r, nil, s+1, f, Knobleft360);
		knobs[i][0] = t;
		r.min.y += Dy(t) + 2*style.margin;
		f = (i-4)*0.2;
		sprint(s, "%+g", f);
		if (s[2] != 0)
			s[1] = s[0];
		knobs[i][1] = knob(r, nil, s+1, f, Knobtop180|Knobvaluebot);
		r = t;
		r.min.x += Dx(r) + 2*style.margin;
	}
	flushimage(display, 1);
	unlockdisplay(display);
}
void
threadmain(int argc, char **argv)
{
	Mousectl *mctl;
	Keyboardctl *kctl;
	Rune key;
	Mouse m;
	int n, oldbuttons;
	Point oldxy;
	float zoom, oldzoom;
	Style s;
	Alt a[] = {
		{ nil, &m, CHANRCV },
		{ nil, nil, CHANRCV },
		{ nil, &key, CHANRCV },
		{ nil, nil, CHANEND },
	};
	USED(argc); USED(argv);
	if (initdraw(nil, nil, "daw/ui") < 0)
		sysfatal("initdraw: %r");
	style.font = font;
	display->locking = 1;
	unlockdisplay(display);
	if ((mctl = initmouse(nil, screen)) == nil)
		sysfatal("initmouse: %r");
	if ((kctl = initkeyboard(nil)) == nil)
		sysfatal("initkeyboard: %r");
	for (n = 0; n < Numcolors; n++)
		color[n] = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1, theme[n].color<<8 | 0xff);
	a[0].c = mctl->c;
	a[1].c = mctl->resizec;
	a[2].c = kctl->c;
	threadsetname("daw/ui");
	redraw();
	oldbuttons = 0;
	oldxy = ZP;
	memmove(&s, &style, sizeof(s));
	oldzoom = 1.0f;
	for (;;) {
		switch (alt(a)) {
		case 0: /* mouse */
			if (m.buttons == 2) {
				if (oldbuttons == 0) {
					oldxy = m.xy;
				} else if (oldbuttons == 2) {
					zoom = MAX(0, oldzoom + m.xy.y-oldxy.y);
					style.knob.r = s.knob.r*(1 + zoom/100.f);
					style.knob.w = s.knob.w*(1 + zoom/100.f);
					redraw();
				}
			} else if (m.buttons == 0) {
				if (oldbuttons == 2)
					oldzoom = zoom;
			}
			oldbuttons = m.buttons;
			break;
		case 1: /* resize */
			getwindow(display, Refnone);
			redraw();
			break;
		case 2: /* keyboard */
			switch (key) {
			case Kdel:
				goto end;
			}
			break;
		}
	}
end:
	threadexitsall(nil);
}