ref: f38288c2e207d8dc2a2fe433462462d57978da43
parent: 5d2c9a4de9139939b456ddb2ddd332365dfb3910
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sun Jan 12 14:01:34 EST 2020
cfg: configuring DSPs through a GUI
--- a/cfg/cfg.c
+++ b/cfg/cfg.c
@@ -1,12 +1,17 @@
#include <u.h>
#include <libc.h>
+#include <bio.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <thread.h>
+#include <microui.h>
#include "common.h"
-#include "nk.h"
+enum {
+ Hasclone = 1<<0,
+};
+
typedef struct UI UI;
struct UI {
@@ -21,23 +26,293 @@
double step;
int ctl;
+ int flags;
+ char *group;
+ char *name;
+ char *unit;
+
char *path;
- UI *child;
+ UI **child;
int numchild;
+
+ /* µui stuff goes here */
+ mu_Container *win;
+ int show;
};
int mainstacksize = 32768;
-static Mousectl *mctl;
-static Keyboardctl *kctl;
-static Image *cola, *colb;
-static Font *f;
static char **dirs;
-static UI topui;
-static struct nk_context nk;
+static UI **top;
+static int numtop;
+static int
+readmeta(UI *ui, char *path)
+{
+ Biobuf *b;
+ char *s, *k;
+ int index;
+
+ if ((b = Bopen(path, OREAD)) == nil)
+ return -1;
+
+ ui->group = ui->name = ui->unit = nil;
+ ui->index = -1;
+ for (; (s = Brdstr(b, '\n', 1)) != nil; free(s)) {
+ if ((k = strtok(s, "\t")) == nil)
+ continue;
+ if (strcmp(k, "group") == 0) /* FIXME more than one group? */
+ ui->group = strdup(strtok(nil, "\t"));
+ else if (strcmp(k, "name") == 0)
+ ui->name = strdup(strtok(nil, "\t"));
+ else if (strcmp(k, "unit") == 0)
+ ui->unit = strdup(strtok(nil, "\t"));
+ else if ((index = strtol(k, &k, 10)) >= 0 && *k == 0)
+ ui->index = index;
+ }
+
+ Bterm(b);
+ return 0;
+}
+
+static int
+readctl(UI *ui)
+{
+ Biobuf b;
+ char *s, *k;
+ int i;
+
+ ui->type = -1;
+ ui->show = 1; /* show everything by default */
+ seek(ui->ctl, 0, 0);
+ Binit(&b, ui->ctl, OREAD);
+
+ if ((s = Brdstr(&b, '\n', 1)) != nil && (k = strtok(s, "\t")) != nil) {
+ for (i = 0; i < nelem(uitypenames); i++) {
+ if (strcmp(k, uitypenames[i]) == 0) {
+ ui->type = i;
+ break;
+ }
+ }
+
+ switch (ui->type) {
+ case UITGroup:
+ case UIHGroup:
+ case UIVGroup:
+ break;
+ case UIButton:
+ case UICheckBox:
+ ui->value = atof(strtok(nil, "\t"));
+ break;
+ case UIVSlider:
+ case UIHSlider:
+ case UINEntry:
+ ui->value = atof(strtok(nil, "\t"));
+ ui->init = atof(strtok(nil, "\t"));
+ ui->min = atof(strtok(nil, "\t"));
+ ui->max = atof(strtok(nil, "\t"));
+ ui->step = atof(strtok(nil, "\t"));
+ break;
+ case UIHBarGraph:
+ case UIVBarGraph:
+ ui->min = atof(strtok(nil, "\t"));
+ ui->max = atof(strtok(nil, "\t"));
+ break;
+ }
+ }
+ free(s);
+
+ Bterm(&b);
+ return 0;
+}
+
+static UI *
+newui(char *path)
+{
+ UI *ui;
+ Dir *dirs;
+ char *s, *name;
+ long i, n;
+ int f;
+
+ if ((f = open(path, OREAD)) < 0)
+ return nil;
+ ui = calloc(1, sizeof(*ui));
+ ui->path = strdup(path);
+ ui->ctl = -1;
+ if ((ui->label = strrchr(ui->path, '/')) == nil)
+ ui->label = ui->path;
+ else
+ ui->label++;
+
+ while ((n = dirread(f, &dirs)) > 0) {
+ for (i = 0; i < n; i++) {
+ name = dirs[i].name;
+ s = smprint("%s/%s", path, name);
+ if (strcmp(name, "metadata") == 0) {
+ readmeta(ui, s);
+ } else if (strcmp(name, "clone") == 0) {
+ ui->flags |= Hasclone;
+ } else if (strcmp(name, "ctl") == 0) {
+ ui->ctl = open(s, ORDWR);
+ readctl(ui);
+ } else if (dirs[i].mode & DMDIR) {
+ ui->child = realloc(ui->child, (ui->numchild+1) * sizeof(*ui->child));
+ ui->child[ui->numchild++] = newui(s);
+ }
+ free(s);
+ }
+ }
+ close(f);
+
+ return ui;
+}
+
static void
+printui(UI *ui, int indent)
+{
+ static char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+ int i;
+
+ print("%.*sui (%s)\n", indent, tabs, ui->path);
+ if (ui->group != nil)
+ print("%.*sgroup: %s\n", indent+1, tabs, ui->group);
+ if (ui->name != nil)
+ print("%.*sname: %s\n", indent+1, tabs, ui->name);
+ print("%.*slabel: %s\n", indent+1, tabs, ui->label);
+ print("%.*sindex: %d\n", indent+1, tabs, ui->index);
+ if (ui->type >= 0)
+ print("%.*stype: %s\n", indent+1, tabs, uitypenames[ui->type]);
+ for (i = 0; i < ui->numchild; i++)
+ printui(ui->child[i], indent+1);
+}
+
+static void
+process_ui(UI *w)
+{
+ UI *c, *slider;
+ double v;
+ int i, state, n, widths[32], maxwidth, x;
+ char tmp[256];
+
+ slider = nil;
+ for (i = 0; i < w->numchild; i++) {
+ c = w->child[i];
+
+ if (slider != nil && c->type != UIVSlider && c->type != UIHSlider) {
+ widths[0] = -1;
+ mu_layout_row(1, widths, 0);
+ slider = nil;
+ }
+
+ switch (c->type) {
+ case UIHGroup: /* FIXME use mu_layout_row/mu_layout_begin_column here */
+ case UITGroup: /* FIXME no tgroup in µui yet */
+ case UIVGroup:
+ if (mu_header(&c->show, c->label))
+ process_ui(c);
+ break;
+ case UIButton:
+ if ((state = mu_button(c->label)) != !!c->value) {
+ if (write(c->ctl, state ? "1" : "0", 1) > 0)
+ c->value = state;
+ }
+ break;
+ case UICheckBox:
+ state = !!c->value;
+ if (mu_checkbox(&state, c->label) & MU_RES_CHANGE) {
+ if (write(c->ctl, state ? "1" : "0", 1) > 0)
+ c->value = state;
+ }
+ break;
+ case UIVSlider: /* FIXME no vslider in µui yet */
+ case UIHSlider:
+ if (slider == nil) {
+ slider = c;
+ maxwidth = 0;
+ for (n = i; n < w->numchild; n++) {
+ if (w->child[n]->type != UIVSlider && w->child[n]->type != UIHSlider)
+ break;
+ if ((x = stringwidth(mu_style.font, w->child[n]->label)) > maxwidth)
+ maxwidth = x;
+ }
+ widths[0] = maxwidth + stringwidth(mu_style.font, ": ");
+ widths[1] = -1;
+ mu_layout_row(2, widths, 0);
+ }
+
+ snprint(tmp, sizeof(tmp), "%s: ", c->label);
+ mu_label(tmp);
+ mu_push_id(&c, sizeof(c));
+ v = c->value;
+ if (mu_slider_ex(&v, c->min, c->max, c->step, "%g", MU_OPT_ALIGNCENTER) & MU_RES_CHANGE) {
+ if (fabs(fabs(v) - fabs(c->value)) >= c->step) {
+ n = snprint(tmp, sizeof(tmp), "%g", v);
+ if (write(c->ctl, tmp, n) > 0)
+ c->value = v;
+ }
+ }
+ mu_pop_id();
+ case UINEntry:
+ break;
+ case UIHBarGraph:
+ case UIVBarGraph:
+ /* FIXME */
+ break;
+ }
+ }
+}
+
+static void
+process_frame(void)
+{
+ UI *ui, *ch;
+ char tmp[128], *s;
+ int i, j;
+
+ mu_begin();
+ for (i = 0; i < numtop; i++) {
+ ui = top[i];
+ for (j = 0; j < ui->numchild; j++) {
+ ch = ui->child[j]->child[0];
+
+ s = ui->child[j]->path;
+ /* remove the annoying "./" if current dir was used */
+ /* FIXME perhaps a prefix common for all dirs should be removed too */
+ if (s[0] == '.' && s[1] == '/')
+ s += 2;
+ snprint(tmp, sizeof(tmp), "[%s] %s", s, ch->label);
+
+ if (mu_begin_window(ch->win, tmp)) {
+ process_ui(ch);
+ mu_end_window();
+ }
+ }
+ }
+ mu_end();
+}
+
+static void
+diradd(char *path)
+{
+ UI *ui, *ch;
+ mu_Container *w;
+ int i;
+
+ top = realloc(top, (numtop+1) * sizeof(*top));
+ ui = newui(path);
+ top[numtop++] = ui;
+ for (i = 0; i < ui->numchild; i++) {
+ ch = ui->child[i]->child[0];
+ ch->win = w = calloc(1, sizeof(*w));
+
+ mu_init_window(w, 0);
+ w->rect = mu_rect(10 + i*210, 10, 200, 400);
+ }
+}
+
+static void
usage(void)
{
print("usage: %s [DIR]...\n", argv0);
@@ -47,6 +322,10 @@
void
threadmain(int argc, char **argv)
{
+ char *s;
+ Biobuf *snarf;
+ Mousectl *mctl;
+ Keyboardctl *kctl;
Rune key;
Mouse m;
Alt a[] = {
@@ -56,7 +335,8 @@
{ nil, nil, CHANEND },
};
char *curdir[] = {".", nil};
- int oldbuttons, x, entering;
+ int oldbuttons, b, nkey, gotevent, i;
+ char text[5];
ARGBEGIN{
default:
@@ -64,8 +344,9 @@
}ARGEND
dirs = *argv == nil ? curdir : argv;
- memset(&topui, 0, sizeof(topui));
- topui.type = -1; /* that one is special */
+ top = nil;
+ for (i = 0; dirs[i] != nil; i++)
+ diradd(dirs[i]);
if (initdraw(nil, nil, "daw/cfg") < 0)
sysfatal("initdraw: %r");
@@ -78,87 +359,81 @@
a[1].c = mctl->resizec;
a[2].c = kctl->c;
- f = display->defaultfont;
- cola = display->white;
- colb = display->black;
srand(time(0));
threadsetname("daw/cfg");
- if (!nk_init_p9(&nk))
- sysfatal("nk_init_p9 failed");
+ mu_init();
+ mu_style.font = font;
+ mu_style.size.y = font->height;
+ mu_style.title_height = mu_style.size.y + 6;
+ process_frame();
oldbuttons = 0;
- entering = 1;
for (;;) {
- nk_glyph g;
- enum nk_keys nkey;
+ process_frame();
+ if (mu_render())
+ flushimage(display, 1);
- nk_input_begin(&nk);
+ gotevent = 1;
+ switch (alt(a)) {
+ case 0: /* mouse */
+ m.xy.x -= screen->r.min.x;
+ m.xy.y -= screen->r.min.y;
+ mu_input_mousemove(m.xy.x, m.xy.y);
+ if ((b = (m.buttons & 1)) != (oldbuttons & 1))
+ (b ? mu_input_mousedown : mu_input_mouseup)(m.xy.x, m.xy.y, MU_MOUSE_LEFT);
+ else if ((b = (m.buttons & 2)) != (oldbuttons & 2))
+ (b ? mu_input_mousedown : mu_input_mouseup)(m.xy.x, m.xy.y, MU_MOUSE_MIDDLE);
+ else if ((b = (m.buttons & 4)) != (oldbuttons & 4))
+ (b ? mu_input_mousedown : mu_input_mouseup)(m.xy.x, m.xy.y, MU_MOUSE_RIGHT);
+ if (m.buttons == 5 && (snarf = Bopen("/dev/snarf", OREAD)) != nil) {
+ if ((s = Brdstr(snarf, 0, 1)) != nil) {
+ mu_input_text(s);
+ free(s);
+ }
+ Bterm(snarf);
+ }
+ oldbuttons = m.buttons;
+ break;
- if (entering == 0) {
- switch (alt(a)) {
- case 0: /* mouse */
- m.xy.x -= screen->r.min.x;
- m.xy.y -= screen->r.min.y;
- nk_input_motion(&nk, m.xy.x, m.xy.y);
- if ((x = (m.buttons & 1)) != (oldbuttons & 1))
- nk_input_button(&nk, NK_BUTTON_LEFT, m.xy.x, m.xy.y, x);
- else if ((x = (m.buttons & 2)) != (oldbuttons & 2))
- nk_input_button(&nk, NK_BUTTON_MIDDLE, m.xy.x, m.xy.y, x);
- else if ((x = (m.buttons & 4)) != (oldbuttons & 4))
- nk_input_button(&nk, NK_BUTTON_RIGHT, m.xy.x, m.xy.y, x);
- oldbuttons = m.buttons;
- break;
+ case 1: /* resize */
+ getwindow(display, Refnone);
+ break;
- case 1: /* resize */
- getwindow(display, Refnone);
- break;
-
- case 2: /* keyboard */
- nkey = -1;
- switch (key) {
- case 'q': goto end;
- case Kbs: nkey = NK_KEY_BACKSPACE; break;
- case Kdel: nkey = NK_KEY_DEL; break;
- case Kleft: nkey = NK_KEY_LEFT; break;
- case Kright: nkey = NK_KEY_RIGHT; break;
- case '\n': nkey = NK_KEY_ENTER; break;
- default:
- if (runetochar(g, &key) > 0)
- nk_input_glyph(&nk, g);
- break;
+ case 2: /* keyboard */
+ nkey = -1;
+ switch (key) {
+ case Kdel: goto end;
+ case Kshift: nkey = MU_KEY_SHIFT; break;
+ case Kbs: nkey = MU_KEY_BACKSPACE; break;
+ case '\n': nkey = MU_KEY_RETURN; break;
+ case Knack: nkey = MU_KEY_NACK; break;
+ case Kleft: nkey = MU_KEY_LEFT; break;
+ case Kright: nkey = MU_KEY_RIGHT; break;
+ case Kesc: mu_set_focus(0); break;
+ default:
+ if (key < 0xf000 || key > 0xffff) {
+ memset(text, 0, sizeof(text));
+ if (runetochar(text, &key) > 0)
+ mu_input_text(text);
}
- if (nkey >= 0) {
- nk_input_key(&nk, nkey, 1);
- nk_input_key(&nk, nkey, 0);
- }
+ break;
}
- } else {
- entering = 0;
- }
+ if (nkey >= 0) {
+ mu_input_keydown(nkey);
+ mu_input_keyup(nkey);
+ }
+ break;
- nk_input_end(&nk);
-
- /* that's just a test */
- if (nk_begin_titled(&nk, "daw/cfg", "daw/cfg", nk_rect(0, 0, Dx(screen->r), Dy(screen->r)), 0)) {
- static int d = 20;
- nk_layout_row_template_begin(&nk, 0);
- nk_layout_row_template_push_static(&nk, stringwidth(display->defaultfont, "Some kind of slider?"));
- nk_layout_row_template_push_variable(&nk, 100);
- nk_layout_row_template_push_static(&nk, stringwidth(display->defaultfont, "Button")*2);
- nk_layout_row_template_end(&nk);
- nk_label(&nk, "Some kind of slider?", NK_TEXT_LEFT);
- nk_slider_int(&nk, 0, &d, 100, 1);
- nk_button_label(&nk, "Button");
+ default:
+ gotevent = 0;
+ break;
}
- nk_end(&nk);
- nk_redraw_p9(&nk, screen);
- nk_clear(&nk);
+ if (gotevent)
+ process_frame();
}
end:
- closemouse(mctl);
- closekeyboard(kctl);
threadexitsall(nil);
}
--- a/cfg/mkfile
+++ b/cfg/mkfile
@@ -4,11 +4,10 @@
cfg\
BIN=/$objtype/bin/daw
-CFLAGS=$CFLAGS -I.. -p
+CFLAGS=$CFLAGS -I..
OFILES=\
common.$O\
cfg.$O\
- nk.$O\
default:V: all