ref: b56d23c78ede1dc4f74b32bc0f6092d87e79553e
dir: /dsp/uiglue.c/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "uiglue.h"
#include "common.h"
#include "aux.h"
static struct {
FAUSTFLOAT *zone;
Meta *meta;
int nummeta;
}decl;
static char *
ui_readstr(UI *ui, int type, char *s, int sz)
{
char *x, *t;
int i;
if (type == Xuictl) {
if (ui->type < 0 || ui->type >= UInum)
sysfatal("unknown ui type %d", ui->type);
t = uitypenames[ui->type];
switch (ui->type) {
case UITGroup:
case UIHGroup:
case UIVGroup:
snprint(s, sz, "%s\n", t);
return s;
case UIButton:
case UICheckBox:
snprint(s, sz, "%s\t%g\n", t, *ui->zone);
return s;
case UIVSlider:
case UIHSlider:
case UINEntry:
snprint(s, sz, "%s\t%g\t%g\t%g\t%g\t%g\n", t, *ui->zone, ui->init, ui->min, ui->max, ui->step);
return s;
case UIHBarGraph:
case UIVBarGraph:
snprint(s, sz, "%s\t%g\t%g\t%g\n", t, *ui->zone, ui->min, ui->max);
return s;
default:
sysfatal("readstr not implemented for ui type %d", ui->type);
}
} else if (type == Xuimeta) {
x = s;
*x = 0;
for (i = 0; i < ui->nummeta; i++)
x = seprint(x, s+sz-1, "%s\t%s\n", ui->meta[i].k, ui->meta[i].v);
return s;
} else {
sysfatal("unknown ui file type %d", type);
}
return nil;
}
static int
ui_write(UI *ui, int type, char *s)
{
char *e;
int failoor;
float v;
if (type != Xuictl)
sysfatal("unknown ui file %d", type);
/* FIXME optional argument should specify at which frame to apply the change */
v = 0.0f;
failoor = 0;
if (strncmp(s, "reset", 5) == 0) { /* FIXME reset for a box should reset ALL controls inside it */
v = ui->init;
} else if (strncmp(s, "add", 3) == 0) {
if (ui->zone != nil)
v = *ui->zone + atof(s+3);
} else if (strncmp(s, "sub", 3) == 0) {
if (ui->zone != nil)
v = *ui->zone - atof(s+3);
} else {
v = strtod(s, &e);
if (*e != 0 && *e != '\n')
return -1;
failoor = 1;
}
if (ui->zone != nil) {
if (ui->type == UIButton || ui->type == UICheckBox) {
*ui->zone = v > 0 ? 1 : 0;
} else {
if (v < ui->min) {
if (failoor)
return -1;
v = ui->min;
} else if (v > ui->max) {
if (failoor)
return -1;
v = ui->max;
}
*ui->zone = v;
}
}
return 0;
}
static UI *
newui(File *f, const char *label, int type)
{
Aux *a;
a = calloc(1, sizeof(*a)+sizeof(UI) + sizeof(Meta)*decl.nummeta);
a->type = Xui;
a->ui = (UI*)(a+1);
a->ui->type = type;
a->ui->meta = (Meta*)(a->ui+1);
a->ui->nummeta = decl.nummeta;
memmove(a->ui->meta, decl.meta, sizeof(Meta)*decl.nummeta);
a->ctl = Xuictl;
a->metadata = Xuimeta;
a->ui->zone = decl.zone;
a->ui->label = label;
a->ui->readstr = ui_readstr;
a->ui->write = ui_write;
if ((uiglue.f = createfile(f, label, nil, DMDIR|0775, a)) == nil)
sysfatal("failed to create ui: %r");
if ((f = createfile(uiglue.f, "ctl", nil, 0664, &a->ctl)) == nil)
sysfatal("failed to create ui ctl: %r");
closefile(f);
if ((f = createfile(uiglue.f, "metadata", nil, 0664, &a->metadata)) == nil)
sysfatal("failed to create ui metadata: %r");
closefile(f);
closefile(uiglue.f);
free(decl.meta);
decl.zone = nil;
decl.meta = nil;
decl.nummeta = 0;
return a->ui;
}
static void
ui_tgroup(void *f, const char *label)
{
newui(f, label, UITGroup);
}
static void
ui_hgroup(void *f, const char *label)
{
newui(f, label, UIHGroup);
}
static void
ui_vgroup(void *f, const char *label)
{
newui(f, label, UIVGroup);
}
static void
ui_close_group(void *file)
{
File *f;
f = file;
uiglue.f = f->parent;
}
static UI *
ui_define(File *f, int type, const char *label, FAUSTFLOAT *zone)
{
UI *ui;
if (zone != decl.zone) { /* no "declare" called before */
decl.zone = zone;
free(decl.meta);
decl.meta = nil;
decl.nummeta = 0;
}
ui = newui(f, label, type);
uiglue.f = f;
return ui;
}
static void
ui_button(void *f, const char *label, FAUSTFLOAT *zone)
{
ui_define(f, UIButton, label, zone);
}
static void
ui_checkbox(void *f, const char *label, FAUSTFLOAT *zone)
{
ui_define(f, UICheckBox, label, zone);
}
static void
ui_vslider(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
UI *ui;
ui = ui_define(f, UIVSlider, label, zone);
ui->init = init;
ui->min = min;
ui->max = max;
ui->step = step;
}
static void
ui_hslider(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
UI *ui;
ui = ui_define(f, UIHSlider, label, zone);
ui->init = init;
ui->min = min;
ui->max = max;
ui->step = step;
}
static void
ui_nentry(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
UI *ui;
ui = ui_define(f, UINEntry, label, zone);
ui->init = init;
ui->min = min;
ui->max = max;
ui->step = step;
}
static void
ui_hbargraph(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
UI *ui;
ui = ui_define(f, UIHBarGraph, label, zone);
ui->min = min;
ui->max = max;
}
static void
ui_vbargraph(void *f, const char *label, FAUSTFLOAT *zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
UI *ui;
ui = ui_define(f, UIVBarGraph, label, zone);
ui->min = min;
ui->max = max;
}
static void
ui_declare(void *f, FAUSTFLOAT *zone, const char *key, const char *value)
{
USED(f);
if (decl.zone != nil && decl.zone != zone)
sysfatal("%s=\"%s\": zone mismatch during declaration (%p != %p)", key, value, decl.zone, zone);
decl.zone = zone;
decl.meta = realloc(decl.meta, sizeof(Meta)*(decl.nummeta+1));
decl.meta[decl.nummeta].k = key;
decl.meta[decl.nummeta].v = value;
decl.nummeta++;
}
UIGlue uiglue = {
.openTabBox = ui_tgroup,
.openHorizontalBox = ui_hgroup,
.openVerticalBox = ui_vgroup,
.closeBox = ui_close_group,
.addButton = ui_button,
.addCheckButton = ui_checkbox,
.addVerticalSlider = ui_vslider,
.addHorizontalSlider = ui_hslider,
.addNumEntry = ui_nentry,
.addHorizontalBargraph = ui_hbargraph,
.addVerticalBargraph = ui_vbargraph,
.declare = ui_declare,
};