ref: a6875be771d0b79f59abe6529231d294094b4a23
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);
}