shithub: guifs

ref: 7aeae86d36a1a04e93bb4be2216cb735acfab714
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 "guifs.h"

#define Eparse "could not parse property"

int
allspace(char *r)
{
	while(*r){
		if(!isspace(*r))
			return 0;
		r++;
	}
	return 1;
}

PropVal
defbackground(void)
{
	PropVal v;
	v.colour = mkcolour(DWhite);
	return v;
}

PropVal
defspacing(void)
{
	PropVal v;
	v.spacing = emalloc(sizeof(Spacing));
	return v;
}

PropVal
deforientation(void)
{
	PropVal v;
	v.orientation = Horizontal;
	return v;
}

PropVal
defbordercolour(void)
{
	PropVal v;
	v.colour = mkcolour(DRed);
	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 *
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;
}

PropVal
getprop(GuiElement *g, int tag)
{
	PropVal *v = nil;
	rlock(&g->lock);
	for(int i = 0; i < g->nprops && v == nil; i++)
		if(g->props[i].tag == tag)
			v = &g->props[i].val;
	runlock(&g->lock);

	if(v == nil)
		sysfatal("invalid prop for this gui element");
	else
		return *v;
}

void
setprop(GuiElement *g, int tag, PropVal val)
{
	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;
	wunlock(&g->lock);
	updategui(0);
}

PropSpec propspecs[Pmax] = {
	[Pbackground] = {"background",	defbackground,	printcolour,	parsecolour},
	[Pborder] = {"border", 	defspacing,	printspacing,	parsespacing},
	[Pmargin] = {"margin", 	defspacing,	printspacing,	parsespacing},
	[Ppadding] = {"padding", defspacing,	printspacing,	parsespacing},
	[Porientation] = {"orientation",	deforientation,	printorientation,	parseorientation},
	[Pbordercolour] = {"bordercolour",	defbordercolour,	printcolour,	parsecolour},
};

int baseprops[nbaseprops] = {Pborder, Pmargin, Ppadding, Pbordercolour};