shithub: guifs

Download patch

ref: 0ad54d136ef33d61172658e97b538f7cd6a91c26
parent: 7aeae86d36a1a04e93bb4be2216cb735acfab714
author: Peter Mikkelsen <petermikkelsen10@gmail.com>
date: Sun Feb 11 11:39:26 EST 2024

Add a basic textbox element

--- a/graphics.c
+++ b/graphics.c
@@ -54,6 +54,10 @@
 	}
 
 	if(Dx(g->rect) > 0 && Dy(g->rect) > 0){
+		/* Draw the background  */
+		Image *bg = getprop(g, Pbackground).colour->image;
+		draw(screen, g->rect, bg, nil, ZP);
+
 		spec.draw(g);
 
 		for(int i = 0; i < g->nchildren; i++)
@@ -65,8 +69,17 @@
 void
 drawcontainer(GuiElement *g)
 {
-	Image *bg = getprop(g, Pbackground).colour->image;
-	draw(screen, g->rect, bg, nil, ZP);
+	USED(g);
+}
+
+void
+drawtextbox(GuiElement *g)
+{
+	Rune *text = getprop(g, Ptext).text;
+	Image *fg = getprop(g, Ptextcolour).colour->image;
+	
+
+	runestring(screen, g->content.min, fg, ZP, font, text);
 }
 
 Colour *
--- a/guifs.h
+++ b/guifs.h
@@ -5,15 +5,18 @@
 	Ppadding,
 	Porientation,
 	Pbordercolour,
+	Ptext,
+	Ptextcolour,
 	Pmax,
 };
 
 enum {
-	nbaseprops = 4
+	nbaseprops = 5
 };
 
 enum {
 	Gcontainer,
+	Gtextbox,
 	Gmax,
 };
 
@@ -46,11 +49,12 @@
 	Colour *colour;
 	Spacing *spacing;
 	int orientation;
+	Rune *text;
 };
 
 struct PropSpec {
 	char *name;
-	PropVal (*def)(void);
+	PropVal (*def)(int, int);
 	char *(*print)(PropVal);
 	char *(*parse)(char *, PropVal *);
 };
@@ -65,6 +69,7 @@
 	char *name;
 	void (*draw)(GuiElement *);
 	void (*layout)(GuiElement *, Rectangle);
+	int leafnode;
 	int nprops;
 	int *proptags;
 };
@@ -91,6 +96,7 @@
 
 	Rectangle border;
 	Rectangle rect;
+	Rectangle content;
 };
 
 extern GuiElement *root;
@@ -99,6 +105,7 @@
 extern int baseprops[nbaseprops];
 
 void *emalloc(ulong);
+int allspace(char *);
 
 Colour *mkcolour(ulong);
 void initgraphics(void);
@@ -105,8 +112,10 @@
 void layout(GuiElement *, Rectangle);
 void updategui(int);
 void drawcontainer(GuiElement *);
+void drawtextbox(GuiElement *);
 
 void layoutcontainer(GuiElement *, Rectangle);
+void layouttextbox(GuiElement *, Rectangle);
 
 PropVal getprop(GuiElement *, int);
 void setprop(GuiElement *, int, PropVal);
\ No newline at end of file
--- a/guispec.c
+++ b/guispec.c
@@ -4,8 +4,10 @@
 
 #include "guifs.h"
 
-int containerprops[] = {Pbackground, Porientation};
+int containerprops[] = {Porientation};
+int textboxprops[] = {Ptext, Ptextcolour};
 
 GuiSpec guispecs[Gmax] = {
-	[Gcontainer] = { "container",	drawcontainer,	layoutcontainer,	nelem(containerprops),	containerprops}
+	[Gcontainer] = { "container",	drawcontainer,	layoutcontainer,	0,	nelem(containerprops),	containerprops},
+	[Gtextbox] = { "textbox",	drawtextbox,	layouttextbox,		1,	nelem(textboxprops),	textboxprops},
 };
\ No newline at end of file
--- a/layout.c
+++ b/layout.c
@@ -35,6 +35,7 @@
 	wlock(&g->lock);
 	g->border = r1;
 	g->rect = r2;
+	g->content = r3;
 	wunlock(&g->lock);
 
 	rlock(&g->lock);
@@ -65,4 +66,11 @@
 		layout(g->children[i], r);
 		r = rectaddpt(r, Pt(dx, dy));
 	}
+}
+
+void
+layouttextbox(GuiElement *g, Rectangle r)
+{
+	USED(g);
+	USED(r);
 }
\ No newline at end of file
--- a/main.c
+++ b/main.c
@@ -101,13 +101,13 @@
 	for(int i = 0; i < nbaseprops; i++){
 		int tag = baseprops[i];
 		props[i].tag = tag;
-		props[i].val = propspecs[tag].def();
+		props[i].val = propspecs[tag].def(type, tag);
 		props[i].qid = mkpropqid(tag);
 	}
 	for(int i = 0; i < spec.nprops; i++){
 		int tag = spec.proptags[i];
 		props[i+nbaseprops].tag = tag;
-		props[i+nbaseprops].val = propspecs[tag].def();
+		props[i+nbaseprops].val = propspecs[tag].def(type, tag);
 		props[i+nbaseprops].qid = mkpropqid(tag);
 	}
 
@@ -195,9 +195,14 @@
 				fid->aux = g->parent;
 				*qid = g->parent->qid;
 			}
-		}else if(strcmp(name, "clone") == 0)
-			*qid = g->qclone;
-		else if(strcmp(name, "event") == 0)
+		}else if(strcmp(name, "clone") == 0){
+			rlock(&g->lock);
+			if(guispecs[g->type].leafnode)
+				err = Eexist;
+			else
+				*qid = g->qclone;
+			runlock(&g->lock);
+		}else if(strcmp(name, "event") == 0)
 			*qid = g->qevent;
 		else if(strcmp(name, "type") == 0)
 			*qid = g->qtype;
@@ -304,6 +309,11 @@
 	d->gid = estrdup9p(username);
 	d->muid = estrdup9p(username);
 
+	rlock(&g->lock);
+	if(guispecs[g->type].leafnode)
+		n++;
+	runlock(&g->lock);
+
 	if(n < Fmax){
 		d->length = 0;
 
@@ -427,7 +437,31 @@
 	
 	switch(QID_TYPE(r->fid->qid)){
 	case Qtype:
-		err = "Can't switch type";
+		{
+			char *buf = emalloc(r->ifcall.count + 1);
+			buf[r->ifcall.count] = 0;
+			memcpy(buf, r->ifcall.data, r->ifcall.count);
+
+			int type;
+			for(type = 0; type < Gmax; type++){
+				char *name = guispecs[type].name;
+				int len = strlen(name);
+				if(strncmp(buf, name, len) == 0 && allspace(buf+len)){
+					rlock(&g->lock);
+					int canswitch = (g->nchildren == 0 || guispecs[type].leafnode == 0);
+					runlock(&g->lock);
+
+					if(canswitch)
+						settype(g, type);
+					else
+						err = "old node has children, and new node type can't";
+					break;
+				}
+			}
+			if(type == Gmax)
+				err = "no such gui element type";
+			free(buf);
+		}
 		break;
 	case Qprop:
 		{
--- a/props.c
+++ b/props.c
@@ -22,24 +22,75 @@
 }
 
 PropVal
-defbackground(void)
+defcolour(int gtag, int ptag)
 {
 	PropVal v;
-	v.colour = mkcolour(DWhite);
+	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(void)
+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(void)
+deforientation(int gtag, int ptag)
 {
+	USED(gtag);
+	USED(ptag);
+
 	PropVal v;
 	v.orientation = Horizontal;
 	return v;
@@ -46,10 +97,14 @@
 }
 
 PropVal
-defbordercolour(void)
+deftext(int gtag, int ptag)
 {
+	USED(gtag);
+	USED(ptag);
+
 	PropVal v;
-	v.colour = mkcolour(DRed);
+	v.text = emalloc(sizeof(Rune));
+	v.text[0] = 0;
 	return v;
 }
 
@@ -90,6 +145,15 @@
 }
 
 char *
+printtext(PropVal p)
+{
+	char *str = smprint("%S", p.text);
+	if(str == nil)
+		sysfatal("smprint failed");
+	return str;
+}
+
+char *
 parsecolour(char *str, PropVal *p)
 {
 	char *r;
@@ -151,6 +215,16 @@
 	return nil;
 }
 
+char *
+parsetext(char *str, PropVal *p)
+{
+	Rune *rstr = runesmprint("%s", str);
+	if(rstr == nil)
+		sysfatal("runesmprint failed");
+	(*p).text = rstr;
+	return nil;
+}
+
 PropVal
 getprop(GuiElement *g, int tag)
 {
@@ -180,12 +254,14 @@
 }
 
 PropSpec propspecs[Pmax] = {
-	[Pbackground] = {"background",	defbackground,	printcolour,	parsecolour},
+	[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",	defbordercolour,	printcolour,	parsecolour},
+	[Pbordercolour] = {"bordercolour",	defcolour,	printcolour,	parsecolour},
+	[Ptext] = {"text",	deftext,	printtext,	parsetext},
+	[Ptextcolour] = {"textcolour",	defcolour,	printcolour,	parsecolour},
 };
 
-int baseprops[nbaseprops] = {Pborder, Pmargin, Ppadding, Pbordercolour};
\ No newline at end of file
+int baseprops[nbaseprops] = {Pbackground, Pborder, Pmargin, Ppadding, Pbordercolour};
\ No newline at end of file
--- a/test.rc
+++ b/test.rc
@@ -9,10 +9,22 @@
 dir=/mnt/gui
 sleep $delay
 
+# split the window vertically into two, and make the top one a textbox
+echo vertical >> $dir/props/orientation
+textdir=$dir/`{cat $dir/clone}
+echo textbox >> $textdir/type
+
+fn show {
+	echo -n $* >> $textdir/props/text
+}
+
+dir=$dir/`{cat $dir/clone}
+
 colours=(FF0000 00FF00 0000FF FFFF00 00FFFF FF00FF FFFFFF 333333)
 for(colour in $colours){
 	dir=$dir/`{cat $dir/clone}			# Create a new sub element in the gui (for now, always a "container")
 	echo $colour^FF >> $dir/props/background	# Set the background
+	show 'setting background of '^$dir^' to 0x'^$colour
 	sleep $delay					# Wait a bit
 }
 
@@ -20,6 +32,7 @@
 for(colour in $colours){
 	subdir=$dir/`{cat $dir/clone}
 	echo $colour^FF >> $subdir/props/background
+	show 'setting background of '^$subdir^' to 0x'^$colour
 	sleep $delay
 }
 
@@ -26,6 +39,7 @@
 # Add some padding to all elements
 for(f in `{walk /mnt/gui/ | grep 'padding$'}){
 	echo 10 >> $f
+	show 'echo 10 >> '^$f
 	sleep $delay
 }
 
@@ -33,6 +47,7 @@
 for(f in `{walk /mnt/gui | grep $dir'/[0-9]+/props/border$'}){
 	echo 8888CCFF >> $f^colour
 	echo 5 >> $f
+	show 'echo 5 >> '^$f
 	sleep $delay
 }
 
@@ -39,11 +54,13 @@
 # Add some margin to the innermost elements
 for(f in `{walk /mnt/gui | grep $dir'/[0-9]+/props/margin'}){
 	echo 5 >> $f
+	show 'echo 5 >> '^$f
 	sleep $delay
 }
 
 # Make the inner container vertical
 echo vertical >> $dir/props/orientation
+show 'echo vertical >> '^$dir/props/orientation
 
 # when the script ends, the old text window draws over the gui. I will fix that later.
 # For now, i just make the script sleep for a long time