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};