#include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include "common.h"#include "ui.h"#include "fs.h"#include "uiglue.h" static struct { float *zone; Meta *meta; int nummeta; int autovoice; int crossvoice;}decl; File *uif;State *uis; char *ui_readstr(UI *ui, int auxtype, char *s, int sz){ char *x, *t; int i; if (auxtype == 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%s%s\n", t, *ui->zone, ui->autovoice ? "\tautovoice" : "", ui->crossvoice ? "\tcrossvoice" : "" ); 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 (auxtype == 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("unsupported ui aux %d", auxtype); } return nil;} intui_writestr(UI *ui, int auxtype, char *s){ char *e; int failoor; float v; if (auxtype != Xuictl) sysfatal("unsupported ui aux %d", auxtype); /* 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(const char *label, int type){ Aux *a; File *f, *d; 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->state = uis; a->ui->zone = decl.zone; a->ui->autovoice = decl.autovoice; a->ui->crossvoice = decl.crossvoice; a->ui->label = label; a->ui->readstr = ui_readstr; a->ui->writestr = ui_writestr; if ((d = createfile(uif, label, nil, DMDIR|0775, a)) == nil) sysfatal("failed to create '%s': %r", label); if ((f = createfile(d, "ctl", nil, 0664, &a->ctl)) == nil) sysfatal("failed to create '%s/ctl': %r", label); closefile(f); if ((f = createfile(d, "metadata", nil, 0664, &a->metadata)) == nil) sysfatal("failed to create '%s/metadata': %r", label); closefile(f); closefile(d); free(decl.meta); decl.zone = nil; decl.meta = nil; decl.nummeta = 0; decl.autovoice = 0; decl.crossvoice = 0; if (type == UITGroup || type == UIHGroup || type == UIVGroup) uif = d; return a->ui;} static UI *newdef(int type, const char *label, float *zone){ if (zone != decl.zone) { /* no "declare" called before */ decl.zone = zone; free(decl.meta); decl.meta = nil; decl.nummeta = 0; } return newui(label, type);} voidui_tgroup(const char *label){ newui(label, UITGroup);} voidui_hgroup(const char *label){ newui(label, UIHGroup);} voidui_vgroup(const char *label){ newui(label, UIVGroup);} voidui_endgroup(void){ uif = uif->parent;} UI *ui_button(const char *label, float *zone){ UI *ui; ui = newdef(UIButton, label, zone); *zone = 0; return ui;} UI *ui_checkbox(const char *label, float *zone){ UI *ui; ui = newdef(UICheckBox, label, zone); *zone = 0; return ui;} UI *ui_vslider(const char *label, float *zone, float init, float min, float max, float step){ UI *ui; ui = newdef(UIVSlider, label, zone); ui->init = *zone = init; ui->min = min; ui->max = max; ui->step = step; return ui;} UI *ui_hslider(const char *label, float *zone, float init, float min, float max, float step){ UI *ui; ui = newdef(UIHSlider, label, zone); ui->init = *zone = init; ui->min = min; ui->max = max; ui->step = step; return ui;} UI *ui_nentry(const char *label, float *zone, float init, float min, float max, float step){ UI *ui; ui = newdef(UINEntry, label, zone); ui->init = *zone = init; ui->min = min; ui->max = max; ui->step = step; return ui;} UI *ui_hbargraph(const char *label, float *zone, float min, float max){ UI *ui; ui = newdef(UIHBarGraph, label, zone); ui->min = min; ui->max = max; *zone = 0; return ui;} UI *ui_vbargraph(const char *label, float *zone, float min, float max){ UI *ui; ui = newdef(UIVBarGraph, label, zone); ui->min = min; ui->max = max; *zone = 0; return ui;} voidui_declare(float *zone, const char *key, const char *value){ 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++; if (strcmp(key, "autovoice") == 0) decl.autovoice = 1; else if (strcmp(key, "crossvoice") == 0) decl.crossvoice = 1;}
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "common.h"
#include "ui.h"
#include "fs.h"
#include "uiglue.h"
static struct {
float *zone;
Meta *meta;
int nummeta;
int autovoice;
int crossvoice;
}decl;
File *uif;
State *uis;
char *
ui_readstr(UI *ui, int auxtype, char *s, int sz)
{
char *x, *t;
int i;
if (auxtype == 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%s%s\n", t, *ui->zone,
ui->autovoice ? "\tautovoice" : "",
ui->crossvoice ? "\tcrossvoice" : ""
);
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 (auxtype == 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("unsupported ui aux %d", auxtype);
}
return nil;
}
int
ui_writestr(UI *ui, int auxtype, char *s)
{
char *e;
int failoor;
float v;
if (auxtype != Xuictl)
sysfatal("unsupported ui aux %d", auxtype);
/* 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(const char *label, int type)
{
Aux *a;
File *f, *d;
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->state = uis;
a->ui->zone = decl.zone;
a->ui->autovoice = decl.autovoice;
a->ui->crossvoice = decl.crossvoice;
a->ui->label = label;
a->ui->readstr = ui_readstr;
a->ui->writestr = ui_writestr;
if ((d = createfile(uif, label, nil, DMDIR|0775, a)) == nil)
sysfatal("failed to create '%s': %r", label);
if ((f = createfile(d, "ctl", nil, 0664, &a->ctl)) == nil)
sysfatal("failed to create '%s/ctl': %r", label);
closefile(f);
if ((f = createfile(d, "metadata", nil, 0664, &a->metadata)) == nil)
sysfatal("failed to create '%s/metadata': %r", label);
closefile(f);
closefile(d);
free(decl.meta);
decl.zone = nil;
decl.meta = nil;
decl.nummeta = 0;
decl.autovoice = 0;
decl.crossvoice = 0;
if (type == UITGroup || type == UIHGroup || type == UIVGroup)
uif = d;
return a->ui;
}
static UI *
newdef(int type, const char *label, float *zone)
{
if (zone != decl.zone) { /* no "declare" called before */
decl.zone = zone;
free(decl.meta);
decl.meta = nil;
decl.nummeta = 0;
}
return newui(label, type);
}
void
ui_tgroup(const char *label)
{
newui(label, UITGroup);
}
void
ui_hgroup(const char *label)
{
newui(label, UIHGroup);
}
void
ui_vgroup(const char *label)
{
newui(label, UIVGroup);
}
void
ui_endgroup(void)
{
uif = uif->parent;
}
UI *
ui_button(const char *label, float *zone)
{
UI *ui;
ui = newdef(UIButton, label, zone);
*zone = 0;
return ui;
}
UI *
ui_checkbox(const char *label, float *zone)
{
UI *ui;
ui = newdef(UICheckBox, label, zone);
*zone = 0;
return ui;
}
UI *
ui_vslider(const char *label, float *zone, float init, float min, float max, float step)
{
UI *ui;
ui = newdef(UIVSlider, label, zone);
ui->init = *zone = init;
ui->min = min;
ui->max = max;
ui->step = step;
return ui;
}
UI *
ui_hslider(const char *label, float *zone, float init, float min, float max, float step)
{
UI *ui;
ui = newdef(UIHSlider, label, zone);
ui->init = *zone = init;
ui->min = min;
ui->max = max;
ui->step = step;
return ui;
}
UI *
ui_nentry(const char *label, float *zone, float init, float min, float max, float step)
{
UI *ui;
ui = newdef(UINEntry, label, zone);
ui->init = *zone = init;
ui->min = min;
ui->max = max;
ui->step = step;
return ui;
}
UI *
ui_hbargraph(const char *label, float *zone, float min, float max)
{
UI *ui;
ui = newdef(UIHBarGraph, label, zone);
ui->min = min;
ui->max = max;
*zone = 0;
return ui;
}
UI *
ui_vbargraph(const char *label, float *zone, float min, float max)
{
UI *ui;
ui = newdef(UIVBarGraph, label, zone);
ui->min = min;
ui->max = max;
*zone = 0;
return ui;
}
void
ui_declare(float *zone, const char *key, const char *value)
{
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++;
if (strcmp(key, "autovoice") == 0)
decl.autovoice = 1;
else if (strcmp(key, "crossvoice") == 0)
decl.crossvoice = 1;
}