ref: c51962a648b3f38fc378ad0081b1d1aa037142d5
dir: /props.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <ctype.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include <mouse.h>
#include "guifs.h"
#define Eparse "could not parse property"
int
allspace(char *r)
{
while(*r){
if(!isspace(*r))
return 0;
r++;
}
return 1;
}
PropVal
defcolour(int gtag, int ptag)
{
PropVal v;
ulong col = DTransparent;
switch(ptag){
case Pbackground:
switch(gtag){
case Gcontainer:
col = DWhite;
break;
case Gtextbox:
col = 0xFFFFEAFF;
break;
}
break;
case Pbordercolour:
switch(gtag){
case Gtextbox:
col = DYellowgreen;
break;
default:
col = DRed;
break;
}
break;
case Ptextcolour:
col = DBlack;
break;
}
v.colour = mkcolour(col);
return v;
}
PropVal
defspacing(int gtag, int ptag)
{
PropVal v;
v.spacing = emalloc(sizeof(Spacing));
int space = 0;
switch(ptag){
case Pborder:
switch(gtag){
case Gtextbox:
space = 4;
break;
}
break;
case Ppadding:
switch(gtag){
case Gtextbox:
space = 2;
break;
}
break;
}
v.spacing->up = v.spacing->down = v.spacing->left = v.spacing->right = space;
return v;
}
PropVal
deforientation(int gtag, int ptag)
{
USED(gtag);
USED(ptag);
PropVal v;
v.orientation = Horizontal;
return v;
}
PropVal
deftext(int gtag, int ptag)
{
USED(gtag);
USED(ptag);
PropVal v;
v.text = emalloc(sizeof(Rune));
v.text[0] = 0;
return v;
}
PropVal
defmenus(int gtag, int ptag)
{
USED(gtag);
USED(ptag);
PropVal v;
v.menus = emalloc(sizeof(MenuSpec));
return v;
}
char *
printcolour(PropVal p)
{
int bufsize = 64;
char *buf = emalloc(bufsize);
snprint(buf, bufsize, "%08ulX\n", p.colour->code);
return buf;
}
char *
printspacing(PropVal p)
{
int bufsize = 256;
char *buf = emalloc(bufsize);
snprint(buf, bufsize, "%d %d %d %d\n", p.spacing->up, p.spacing->right, p.spacing->down, p.spacing->left);
return buf;
}
char *
printorientation(PropVal p)
{
char *str;
switch(p.orientation){
case Horizontal:
str = estrdup9p("horizontal\n");
break;
case Vertical:
str = estrdup9p("vertical\n");
break;
default:
str = estrdup9p("???\n");
break;
}
return str;
}
char *
printtext(PropVal p)
{
char *str = smprint("%S", p.text);
if(str == nil)
sysfatal("smprint failed");
return str;
}
char *
printmenus(PropVal p)
{
MenuSpec *spec = p.menus;
char which[3] = "LMR";
char *str = smprint("");
for(int i = 0; i < 3; i++){
if(spec->menus[i] == nil)
continue;
char sep = spec->seps[i];
char *tmp = str;
str = smprint("%s%c", tmp, which[i]);
free(tmp);
char **items = spec->menus[i]->item;
for(int j = 0; items[j] != nil; j++){
tmp = str;
str = smprint("%s%c%s", tmp, sep, items[j]);
free(tmp);
}
tmp = str;
str = smprint("%s\n", tmp);
free(tmp);
}
return str;
}
char *
parsecolour(char *str, PropVal *p)
{
char *r;
ulong c = strtoul(str, &r, 16);
if((r - str) != 8 || !allspace(r))
return Eparse;
(*p).colour = mkcolour(c);
return nil;
}
char *
parsespacing(char *str, PropVal *p)
{
USED(p);
char *fields[5];
int spacings[4];
int n = getfields(str, fields, nelem(fields), 0, " ");
if(!(n == 4 || n == 2 || n == 1))
return Eparse;
for(int i = 0; i < n; i++){
char *r;
spacings[i] = strtol(fields[i], &r, 10);
if(!allspace(r))
return Eparse;
}
Spacing *s = emalloc(sizeof(Spacing));
switch(n){
case 1:
s->up = s->down = s->left = s->right = spacings[0];
break;
case 2:
s->up = s->down = spacings[0];
s->left = s->right = spacings[1];
break;
case 4:
s->up = spacings[0];
s->right = spacings[1];
s->down = spacings[2];
s->left = spacings[3];
break;
}
(*p).spacing = s;
return nil;
}
char *
parseorientation(char *str, PropVal *p)
{
if(strncmp(str, "horizontal", 10) == 0 && allspace(str+10))
(*p).orientation = Horizontal;
else if(strncmp(str, "vertical", 8) == 0 && allspace(str+8))
(*p).orientation = Vertical;
else
return Eparse;
return nil;
}
char *
parsetext(char *str, PropVal *p)
{
Rune *rstr = runesmprint("%s", str);
if(rstr == nil)
sysfatal("runesmprint failed");
(*p).text = rstr;
return nil;
}
char *
parsemenus(char *str, PropVal *p)
{
char *err = nil;
int n = 0;
for(int i = 0; str[i] != 0; i++)
if(str[i] == '\n')
n++;
char **lines = emalloc(sizeof(char *) * (n+1));
n = getfields(str, lines, n, 1, "\n");
p->menus = emalloc(sizeof(MenuSpec));
MenuSpec *spec = p->menus;
for(int i = 0; i < n; i++){
char *line = lines[i];
if(strlen(line) == 0)
continue;
if(strlen(line) <= 2)
return Eparse;
int which;
switch(line[0]){
case 'L': which = 0; break;
case 'M': which = 1; break;
case 'R': which = 2; break;
default:
err = Eparse;
goto Lend;
}
if(spec->menus[which] == nil)
spec->menus[which] = emalloc(sizeof(Menu));
int count = 0;
char sep = line[1];
spec->seps[which] = sep;
spec->menus[which]->item = emalloc(sizeof(char *));
char *start = line+2;
char *end;
while(*start != 0){
count++;
spec->menus[which]->item = erealloc(spec->menus[which]->item, sizeof(char *) * count);
for(end = start; *end != 0 && *end != sep && *end != '\n'; end++);
int len = end-start;
char *buf = emalloc(len+1);
memcpy(buf, start, len);
buf[len] = 0;
spec->menus[which]->item[count-1] = buf;
start = end;
if(*start != 0){
do{
start++;
}while(*start == '\n');
}
}
spec->menus[which]->item[count] = nil;
print("count: %d\n", count);
}
Lend:
free(lines);
return err;
}
PropVal
getprop(GuiElement *g, int tag, int lock)
{
PropVal *v = nil;
if(lock)
rlock(&g->lock);
for(int i = 0; i < g->nprops && v == nil; i++)
if(g->props[i].tag == tag)
v = &g->props[i].val;
if(lock)
runlock(&g->lock);
if(v == nil)
sysfatal("invalid prop %d for this gui element", tag);
else
return *v;
}
void
setprop(GuiElement *g, int tag, PropVal val, int lock)
{
if(lock)
wlock(&g->lock);
/* TODO: free old propval */
for(int i = 0; i < g->nprops; i++)
if(g->props[i].tag == tag)
g->props[i].val = val;
if(lock){
wunlock(&g->lock);
updategui(0); /* Can't update gui if the user has write-locked g */
}
}
PropSpec propspecs[Pmax] = {
[Pbackground] = {"background", defcolour, printcolour, parsecolour},
[Pborder] = {"border", defspacing, printspacing, parsespacing},
[Pmargin] = {"margin", defspacing, printspacing, parsespacing},
[Ppadding] = {"padding", defspacing, printspacing, parsespacing},
[Porientation] = {"orientation", deforientation, printorientation, parseorientation},
[Pbordercolour] = {"bordercolour", defcolour, printcolour, parsecolour},
[Ptext] = {"text", deftext, printtext, parsetext},
[Ptextcolour] = {"textcolour", defcolour, printcolour, parsecolour},
[Pmenus] = {"menus", defmenus, printmenus, parsemenus},
};
int baseprops[nbaseprops] = {Pbackground, Pborder, Pmargin, Ppadding, Pbordercolour, Pmenus};