shithub: guifs

ref: c51962a648b3f38fc378ad0081b1d1aa037142d5
dir: /props.c/

View raw version
#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};