ref: 2cbd46b30a19983458bb4b6af4c951321c224818
dir: /cfg/cfg.c/
#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" enum { Hasclone = 1<<0, }; typedef struct UI UI; struct UI { UItype type; const char *label; int index; double value; double init; double min; double max; double step; int ctl; int flags; char *group; char *name; char *unit; char *path; UI **child; int numchild; /* µui stuff goes here */ mu_Container *win; int show; }; int mainstacksize = 32768; static char **dirs; 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; mu_Id id; 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 (mu_button(c->label) & MU_RES_SUBMIT) { if (write(c->ctl, "1", 1) > 0) c->value = 1; } else if (c->value) { id = mu_get_id(c->label, strlen(c->label)); if (mu_ctx.focus != id || mu_ctx.mouse_down != MU_MOUSE_LEFT) { if (write(c->ctl, "0", 1) > 0) c->value = 0; } } break; case UICheckBox: state = !!c->value; if ((mu_checkbox(&state, c->label) & MU_RES_CHANGE) != 0 && 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; snprint(tmp, sizeof(tmp), "%%g%s", c->unit == nil ? "" : c->unit); if (mu_slider_ex(&v, c->min, c->max, c->step, tmp, MU_OPT_ALIGNCENTER) & MU_RES_CHANGE) { 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); threadexitsall("usage"); } void threadmain(int argc, char **argv) { char *s; Biobuf *snarf; Mousectl *mctl; Keyboardctl *kctl; Rune key; Mouse m; Alt a[] = { { nil, &m, CHANRCV }, { nil, nil, CHANRCV }, { nil, &key, CHANRCV }, { nil, nil, CHANEND }, }; char *curdir[] = {".", nil}; int oldbuttons, b, nkey, gotevent, i; char text[5]; ARGBEGIN{ default: usage(); }ARGEND dirs = *argv == nil ? curdir : argv; top = nil; for (i = 0; dirs[i] != nil; i++) diradd(dirs[i]); if (initdraw(nil, nil, "daw/cfg") < 0) sysfatal("initdraw: %r"); if ((mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); if ((kctl = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); a[0].c = mctl->c; a[1].c = mctl->resizec; a[2].c = kctl->c; srand(time(0)); threadsetname("daw/cfg"); 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; for (;;) { process_frame(); if (mu_render()) flushimage(display, 1); 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; case 1: /* resize */ getwindow(display, Refnone); 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); } break; } if (nkey >= 0) { mu_input_keydown(nkey); mu_input_keyup(nkey); } break; default: gotevent = 0; break; } if (gotevent) process_frame(); } end: threadexitsall(nil); }