commit 3b5c78b85d6d703636f52463345da3834480a0c2
parent a9f1b9e8a483e8b8858f6e119a3870b94ad569b9
Author: Renev Pavel <an2qzavok@gmail.com>
Date: Fri, 28 Oct 2022 09:51:37 +0000
add src/knob
Diffstat:
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