stew

a monorepo of some sort
Log | Files | Refs

commit 3b5c78b85d6d703636f52463345da3834480a0c2
parent a9f1b9e8a483e8b8858f6e119a3870b94ad569b9
Author: Renev Pavel <an2qzavok@gmail.com>
Date:   Fri, 28 Oct 2022 09:51:37 +0000

add src/knob

Diffstat:
Asrc/knob/alsa | 8++++++++
Asrc/knob/knob.7 | 0
Asrc/knob/knob.c | 346+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/knob/mkfile | 12++++++++++++
4 files changed, 366 insertions(+), 0 deletions(-)

diff --git a/src/knob/alsa b/src/knob/alsa @@ -0,0 +1,8 @@ +#!/bin/rc + + +receive -p widget | + sed -u 's/(\.[0-9]+)*$/%/'| + os xargs -L 1 amixer -q sset Master & + +echo Master 0 100 75 | knob diff --git a/src/knob/knob.7 b/src/knob/knob.7 Binary files differ. diff --git a/src/knob/knob.c b/src/knob/knob.c @@ -0,0 +1,346 @@ +#include <u.h> +#include <libc.h> +#include <plumb.h> +#include <thread.h> +#include <draw.h> +#include <mouse.h> +#include <bio.h> + + +enum { + KnobSize = (100 - 8), +}; + + +typedef struct Knob Knob; +typedef struct Group Group; + +struct Knob { + char *name; + double min; + double max; + double val; + Rectangle r; +}; + +struct Group { + char *name; + Knob *knobs; + Rectangle r; +}; + +Mousectl *mctl; +Font *microfont; +Image *bg, *groupbg, *fg, *hotfg; +char *plumbport = "widget"; + +Knob *hotknob; +Group g; + +int +knobslen(Knob *k) +{ + int n; + if (k == nil) return 0; + for (n = 0; k[n].name != nil; n++); + return n; +} + +void +appendknob(Group *g, Knob *k) +{ + int n = knobslen(g->knobs); + g->knobs = realloc(g->knobs, sizeof(Knob) * (n + 2)); + g->knobs[n] = *k; + g->knobs[n + 1].name = nil; +} + +void +config(int fd) +{ + Biobuf *bp = Bfdopen(fd, OREAD); + char *str; + while ((str = Brdstr(bp, '\n', 0)) != nil) { + char *args[4]; + int n = tokenize(str, args, 4); + if (n > 0) { + Knob k; + + k.name = args[0]; + + if (n >= 3) { + k.min = strtod(args[1], nil); + k.max = strtod(args[2], nil); + } + if (n == 4) k.val = strtod(args[3], nil); + + appendknob(&g, &k); + } + } + if (fd != 0) close(fd); +} + +void +_drawknob(Rectangle r, double min, double max, double val, Image *src, char *name) +{ + int d, w; + Point C; + char *s; + char buf[64]; + + C = divpt(addpt(r.min, r.max), 2); + s = nil; + + w = stringwidth(microfont, name); + string( + screen, + addpt(r.min, Pt((Dx(r) - w)/2, 0)), + src, ZP, microfont, name + ); + + d = (Dx(r) < Dy(r) - microfont->height * 2) ? + Dx(r) : Dy(r) - microfont->height * 2; + + ellipse( + screen, C, + d / 2, d / 2, 0, src, ZP + ); + if (val > max) { + s = ">"; + } + else if (val < min) { + s = "<"; + } + + if (s != nil) { + w = stringwidth(microfont, s); + string( + screen, + subpt(C, Pt(w/2, microfont->height/2)), + src, ZP, microfont, s + ); + } else { + double p; + int cosp, sinp; + p = (max != min) ? (val - min) / (max - min) : 0; + p = (max != -min) ? p * 360 : p * 270 - 135; + icossin(p, &cosp, &sinp); + line( + screen, + addpt(C, Pt(sinp * d / 4096, - cosp * d / 4096)), + addpt(C, Pt(sinp * d / 2048, - cosp * d / 2048)), + 0, 0, 0, + src, ZP + ); + } + + snprint(buf, 64, "%g", val); + + w = stringwidth(microfont, buf); + string( + screen, + Pt(r.min.x + (Dx(r) - w) / 2, r.max.y - microfont->height), + src, ZP, microfont, buf + ); +} + +void +drawknob(Knob *k) +{ + Image *src; + src = (hotknob == k) ? hotfg : fg; + draw(screen, k->r, bg, nil, ZP); + _drawknob(k->r, k->min, k->max, k->val, src, k->name); +} + +void +drawgroup(Group *g) +{ + draw(screen, + Rpt(g->r.min, Pt(g->r.max.x, g->r.min.y + microfont->height)), + groupbg, nil, ZP + ); + string( + screen, + g->r.min, + fg, ZP, microfont, g->name + ); +} + +void +resize(void) +{ + draw(screen, screen->r, bg, nil, ZP); + + g.r = screen->r; + drawgroup(&g); + + Rectangle r = rectaddpt( + Rect(0, 0, KnobSize, KnobSize), + addpt(screen->r.min, Pt(0, microfont->height)) + ); + + Knob *k; + + for (k = g.knobs; k->name != nil; k++) { + k->r = r; + drawknob(k); + + r = rectaddpt(r, Pt(KnobSize, 0)); + if (r.max.x > screen->r.max.x) { + r = rectaddpt( + Rect(0, 0, KnobSize, KnobSize), + Pt(screen->r.min.x, r.max.y) + ); + } + } +} + +Knob * +findknob(char *name) +{ + if (name == nil) return nil; + if (g.knobs == nil) return nil; + + Knob *k; + + for (k = g.knobs; k->name != nil; k++) { + if (strcmp(name, k->name) == 0) { + return k; + } + } + return nil; +} + +Knob * +findhot(Point xy) +{ + + if (g.knobs == nil) return nil; + + Knob *k; + + for (k = g.knobs; k->name != nil; k++) { + if (ptinrect(xy, k->r) != 0) return k; + } + return nil; +} + +void +threadmouse(void *) +{ + int fd; + fd = plumbopen("send", OWRITE); + if (fd <= 0) sysfatal("threadmouse: %r"); + + Mouse m; + double startval; + Point startxy; + + while(recv(mctl->c, &m) != -1){ + if (m.buttons == 0) { + Knob *k = hotknob; + hotknob = nil; + if (k != nil) { + lockdisplay(display); + drawknob(k); + flushimage(display, 1); + unlockdisplay(display); + } + continue; + } + if (hotknob == nil) { + hotknob = findhot(m.xy); + if (hotknob != nil) { + startval = hotknob->val; + startxy = m.xy; + } + } + if (hotknob != nil) { + double val; + val = startval + (m.xy.y - startxy.y) * (hotknob->max - hotknob->min) / 1000; + if (val > hotknob->max) val = hotknob->max; + if (val < hotknob->min) val = hotknob->min; + + Plumbmsg *msg; + msg = mallocz(sizeof(Plumbmsg), 1); + msg->src = strdup("knob"); + msg->dst = strdup(plumbport); + msg->type = strdup("text"); + msg->data = smprint("%g\n", val); + msg->ndata = strlen(msg->data); + + msg->attr = mallocz(sizeof(Plumbattr), 1); + msg->attr->name = strdup("name"); + msg->attr->value = strdup(hotknob->name); + msg->attr->next = nil; + + plumbsend(fd, msg); + plumbfree(msg); + } + } +} + +void +threaddraw(void *) +{ + + int fd; + Plumbmsg *msg; + fd = plumbopen(plumbport, OREAD); + if (fd <= 0) sysfatal("threaddraw: %r"); + + while((msg = plumbrecv(fd)) != nil){ + char *name = plumblookup(msg->attr, "name"); + plumbfree(msg); + Knob *k = findknob(name); + if (k != nil) { + k->val = strtod(msg->data, nil); + lockdisplay(display); + drawknob(k); + flushimage(display, 1); + unlockdisplay(display); + } + } +} + +void +threadmain(int argc, char **argv) +{ + + g.name = "global"; + + config(0); + + initdraw(nil, nil, "knob"); + display->locking = 1; + + if ((mctl = initmouse(0, screen)) == nil) sysfatal("%r"); + + microfont = openfont(display, "/lib/font/bit/terminus/unicode.12.font"); + + groupbg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DMedblue); + bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DBlack); + fg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DWhite); + hotfg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DRed); + + resize(); + flushimage(display, 1); + + unlockdisplay(display); + + proccreate(threaddraw, nil, 4096 * 1024); + threadcreate(threadmouse, nil, 4096 * 1024); + + for (;;) { + if (recv(mctl->resizec, nil) > 0) { + if (getwindow(display, Refnone) < 0) + sysfatal("resize failed: %r"); + + lockdisplay(display); + resize(); + flushimage(display, 1); + unlockdisplay(display); + } + } +} diff --git a/src/knob/mkfile b/src/knob/mkfile @@ -0,0 +1,12 @@ +</$objtype/mkfile + +all:V: knob + +knob.$O: knob.c + $CC knob.c + +knob: knob.$O + $LD -o knob knob.$O + +clean:V: + rm -rf knob knob.$O