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