shithub: neindaw

ref: 8747033fb429a67053e229b30c323ce1c5a25a54
dir: neindaw/ui/ui.c

View raw version
#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);
}