diff options
author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2024-02-11 15:18:27 +0000 |
---|---|---|
committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2024-02-11 15:18:27 +0000 |
commit | 7aeae86d36a1a04e93bb4be2216cb735acfab714 (patch) | |
tree | 88d113a905ea73fb2f32cc43283bed3decae3e76 | |
parent | 7c6a945996a1d5510ff1412320ac7d07a0f82851 (diff) |
More work
-rw-r--r-- | graphics.c | 81 | ||||
-rw-r--r-- | guifs.h | 35 | ||||
-rw-r--r-- | guispec.c | 5 | ||||
-rw-r--r-- | layout.c | 61 | ||||
-rw-r--r-- | main.c | 124 | ||||
-rw-r--r-- | props.c | 151 | ||||
-rwxr-xr-x | test.rc | 36 |
7 files changed, 388 insertions, 105 deletions
@@ -10,21 +10,56 @@ Mousectl *mouse; Keyboardctl *keyboard; Channel *updatechan; +Channel *mkcolourchan; +Channel *newcolourchan; void drawgui(GuiElement *g) { + rlock(&g->lock); GuiSpec spec = guispecs[g->type]; - spec.draw(g); - for(int i = 0; i < g->nchildren; i++) - drawgui(g->children[i]); -} -void -drawnone(GuiElement *g) -{ - Image *bg = getprop(g, Pbackground).colour->image; - draw(screen, g->rect, bg, nil, ZP); + if(memcmp(&g->rect, &g->border, sizeof(Rectangle)) != 0 && Dx(g->border) > 0 && Dy(g->border) > 0){ + /* draw the border first */ + Image *bc = getprop(g, Pbordercolour).colour->image; + Rectangle r; + + /* top part */ + r.min.x = g->border.min.x; + r.min.y = g->border.min.y; + r.max.x = g->border.max.x; + r.max.y = g->rect.min.y; + draw(screen, r, bc, nil, ZP); + + /* right part */ + r.min.x = g->rect.max.x; + r.min.y = g->rect.min.y; + r.max.x = g->border.max.x; + r.max.y = g->border.max.y; + draw(screen, r, bc, nil, ZP); + + /* bottom part */ + r.min.x = g->border.min.x; + r.min.y = g->rect.max.y; + r.max.x = g->border.max.x; + r.max.y = g->border.max.y; + draw(screen, r, bc, nil, ZP); + + /* left part */ + r.min.x = g->border.min.x; + r.min.y = g->border.min.y; + r.max.x = g->rect.min.x; + r.max.y = g->border.max.y; + draw(screen, r, bc, nil, ZP); + } + + if(Dx(g->rect) > 0 && Dy(g->rect) > 0){ + spec.draw(g); + + for(int i = 0; i < g->nchildren; i++) + drawgui(g->children[i]); + } + runlock(&g->lock); } void @@ -37,13 +72,10 @@ drawcontainer(GuiElement *g) Colour * mkcolour(ulong c) { - lockdisplay(display); - Colour *col = emalloc(sizeof(Colour)); - col->image = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c); - col->code = c; - unlockdisplay(display); - - return col; + Colour *res = nil; + send(mkcolourchan, &c); + recv(newcolourchan, &res); + return res; } void @@ -70,9 +102,9 @@ void guiproc(void *) { int i; + ulong c; if(initdraw(nil, nil, "guifs") < 0) sysfatal("initdraw failed"); - display->locking = 1; if((mouse = initmouse(nil, screen)) == nil) sysfatal("initmouse failed"); @@ -83,6 +115,7 @@ guiproc(void *) Aupdategui, Aresize, Amouse, + Amkcolour, Aaltend, }; Alt a[] = { @@ -92,14 +125,14 @@ guiproc(void *) {mouse->resizec, nil, CHANRCV}, [Amouse] = {mouse->c, &mouse->Mouse, CHANRCV}, + [Amkcolour] = + {mkcolourchan, &c, CHANRCV}, [Aaltend] = {nil, nil, CHANEND}, }; while(1){ - unlockdisplay(display); int which = alt(a); - lockdisplay(display); switch(which){ case Aupdategui: @@ -110,6 +143,14 @@ guiproc(void *) break; case Amouse: break; + case Amkcolour: + { + + Colour *col = emalloc(sizeof(Colour)); + col->image = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c); + col->code = c; + send(newcolourchan, &col); + } } } } @@ -118,6 +159,8 @@ void initgraphics(void) { updatechan = chancreate(sizeof(int), 0); + mkcolourchan = chancreate(sizeof(ulong), 0); + newcolourchan = chancreate(sizeof(Colour *), 0); proccreate(guiproc, nil, mainstacksize); updategui(1); } @@ -1,14 +1,29 @@ enum { Pbackground, + Pborder, + Pmargin, + Ppadding, + Porientation, + Pbordercolour, Pmax, }; enum { - Gnone, + nbaseprops = 4 +}; + +enum { Gcontainer, Gmax, }; + +enum { + Horizontal, + Vertical, +}; + typedef struct Colour Colour; +typedef struct Spacing Spacing; typedef union PropVal PropVal; typedef struct PropSpec PropSpec; typedef struct Prop Prop; @@ -20,8 +35,17 @@ struct Colour { ulong code; }; +struct Spacing { + int up; + int right; + int down; + int left; +}; + union PropVal { Colour *colour; + Spacing *spacing; + int orientation; }; struct PropSpec { @@ -42,10 +66,12 @@ struct GuiSpec { void (*draw)(GuiElement *); void (*layout)(GuiElement *, Rectangle); int nprops; - int proptags[]; + int *proptags; }; struct GuiElement { + RWLock lock; + int type; int id; @@ -63,13 +89,14 @@ struct GuiElement { int nprops; Prop *props; + Rectangle border; Rectangle rect; - }; extern GuiElement *root; extern PropSpec propspecs[Pmax]; extern GuiSpec guispecs[Gmax]; +extern int baseprops[nbaseprops]; void *emalloc(ulong); @@ -77,10 +104,8 @@ Colour *mkcolour(ulong); void initgraphics(void); void layout(GuiElement *, Rectangle); void updategui(int); -void drawnone(GuiElement *); void drawcontainer(GuiElement *); -void layoutnone(GuiElement *, Rectangle); void layoutcontainer(GuiElement *, Rectangle); PropVal getprop(GuiElement *, int); @@ -4,7 +4,8 @@ #include "guifs.h" +int containerprops[] = {Pbackground, Porientation}; + GuiSpec guispecs[Gmax] = { - [Gnone] = { "none", drawnone, layoutnone, 1, {Pbackground}}, - [Gcontainer] = { "container", drawcontainer, layoutcontainer, 1, {Pbackground}}, + [Gcontainer] = { "container", drawcontainer, layoutcontainer, nelem(containerprops), containerprops} };
\ No newline at end of file @@ -4,40 +4,65 @@ #include "guifs.h" -void -layout(GuiElement *g, Rectangle r) +Rectangle +subspacing(Rectangle r, Spacing *s) { - GuiSpec spec = guispecs[g->type]; - - g->rect = r; - spec.layout(g, r); + r.min.x += s->left; + r.min.y += s->up; + r.max.x -= s->right; + r.max.y -= s->down; + return r; } void -layoutnone(GuiElement *g, Rectangle r) +layout(GuiElement *g, Rectangle r0) { - USED(g); - USED(r); + GuiSpec spec = guispecs[g->type]; + + Spacing *margin = getprop(g, Pmargin).spacing; + Spacing *border = getprop(g, Pborder).spacing; + Spacing *padding = getprop(g, Ppadding).spacing; + + /* Subtract margin to get the outer border rect */ + Rectangle r1 = subspacing(r0, margin); + + /* Subtract border widths to get the inner border rect */ + Rectangle r2 = subspacing(r1, border); + + /* Subtract padding to get the content rect */ + Rectangle r3 = subspacing(r2, padding); + + wlock(&g->lock); + g->border = r1; + g->rect = r2; + wunlock(&g->lock); + + rlock(&g->lock); + spec.layout(g, r3); + runlock(&g->lock); } void layoutcontainer(GuiElement *g, Rectangle r) { - USED(g); - USED(r); - if(g->nchildren == 0) return; - int margin = 10; + int orientation = getprop(g, Porientation).orientation; - r = insetrect(r, 10); - int width = Dx(r) - (margin * (g->nchildren - 1)); - width = width / g->nchildren; - r.max.x = r.min.x + width; + int dx = 0; + int dy = 0; + + if(orientation == Horizontal){ + dx = Dx(r) / g->nchildren; + r.max.x = r.min.x + dx; + }else if(orientation == Vertical){ + dy = Dy(r) / g->nchildren; + r.max.y = r.min.y + dy; + } for(int i = 0; i < g->nchildren; i++){ layout(g->children[i], r); - r = rectaddpt(r, Pt(width+margin, 0)); + r = rectaddpt(r, Pt(dx, dy)); } }
\ No newline at end of file @@ -13,6 +13,8 @@ #define Eoffset "can't write to this file at non-zero offset" #define Ebadctl "bad ctl message" +QLock guilock = 0; + char *username; enum { @@ -88,19 +90,35 @@ mkpropqid(int proptag) void settype(GuiElement *g, int type) { + GuiSpec spec = guispecs[type]; - free(g->props); - g->type = type; - - g->nprops = spec.nprops; - g->props = emalloc(sizeof(Prop) * spec.nprops); + int nprops = spec.nprops + nbaseprops; + /* Allocate the props before locking the gui element, as some of the + * allocations might cause this thread to block + */ + + Prop *props = emalloc(sizeof(Prop) * nprops); + for(int i = 0; i < nbaseprops; i++){ + int tag = baseprops[i]; + props[i].tag = tag; + props[i].val = propspecs[tag].def(); + props[i].qid = mkpropqid(tag); + } for(int i = 0; i < spec.nprops; i++){ int tag = spec.proptags[i]; - g->props[i].tag = tag; - g->props[i].val = propspecs[tag].def(); - g->props[i].qid = mkpropqid(tag); + props[i+nbaseprops].tag = tag; + props[i+nbaseprops].val = propspecs[tag].def(); + props[i+nbaseprops].qid = mkpropqid(tag); } + wlock(&g->lock); + /* TODO: free old propvals */ + free(g->props); + g->type = type; + g->nprops = nprops; + g->props = props; + wunlock(&g->lock); + updategui(0); /* redraw everything */ } @@ -108,7 +126,6 @@ GuiElement * newgui(GuiElement *parent) { GuiElement *g = emalloc(sizeof(GuiElement)); - memset(g, 0, sizeof(GuiElement)); g->parent = parent; g->qid = mkqid(Qdir); g->qclone = mkqid(Qclone); @@ -118,9 +135,11 @@ newgui(GuiElement *parent) if(parent){ g->id = parent->nchildren; + wlock(&parent->lock); parent->nchildren++; parent->children = erealloc(parent->children, parent->nchildren * sizeof(GuiElement *)); parent->children[g->id] = g; + wunlock(&parent->lock); } settype(g, Gcontainer); @@ -137,10 +156,11 @@ findchild(GuiElement *g, char *name) return nil; } - if(id < g->nchildren) - return g->children[id]; + rlock(&g->lock); + GuiElement *child = (id < g->nchildren) ? g->children[id] : nil; + runlock(&g->lock); - return nil; + return child; } void @@ -164,6 +184,7 @@ fswalk1(Fid *fid, char *name, Qid *qid) { GuiElement *g = fid->aux; GuiElement *child; + char *err = nil; switch(QID_TYPE(fid->qid)){ case Qdir: @@ -174,41 +195,43 @@ fswalk1(Fid *fid, char *name, Qid *qid) fid->aux = g->parent; *qid = g->parent->qid; } - return nil; - }else if(strcmp(name, "clone") == 0){ + }else if(strcmp(name, "clone") == 0) *qid = g->qclone; - return nil; - }else if(strcmp(name, "event") == 0){ + else if(strcmp(name, "event") == 0) *qid = g->qevent; - return nil; - }else if(strcmp(name, "type") == 0){ + else if(strcmp(name, "type") == 0) *qid = g->qtype; - return nil; - }else if(strcmp(name, "props") == 0){ + else if(strcmp(name, "props") == 0) *qid = g->qprops; - return nil; - }else if(child = findchild(g, name)){ + else if(child = findchild(g, name)){ fid->aux = child; *qid = child->qid; - return nil; - } - return Eexist; + }else + err = Eexist; + break; case Qprops: - if(strcmp(name, "..") == 0){ + if(strcmp(name, "..") == 0) *qid = g->qid; - return nil; - } - for(int i = 0; i < g->nprops; i++){ - PropSpec spec = propspecs[g->props[i].tag]; - if(strcmp(name, spec.name) == 0){ - *qid = g->props[i].qid; - return nil; + else{ + rlock(&g->lock); + int ok = 0; + for(int i = 0; i < g->nprops && ok == 0; i++){ + PropSpec spec = propspecs[g->props[i].tag]; + if(strcmp(name, spec.name) == 0){ + *qid = g->props[i].qid; + ok = 1; + } } + runlock(&g->lock); + if(!ok) + err = Eexist; } - return Eexist; + break; default: - return Enodir; + err = Enodir; + break; } + return err; } char * @@ -310,7 +333,10 @@ dirtreegen(int n, Dir *d, void *aux) }else n -= Fmax; - if(g && n < g->nchildren){ + rlock(&g->lock); + int done = n >= g->nchildren; + + if(!done){ GuiElement *child = g->children[n]; d->mode = DMDIR|0555; @@ -319,10 +345,10 @@ dirtreegen(int n, Dir *d, void *aux) char buf[64]; snprint(buf, sizeof(buf), "%d", child->id); d->name = estrdup9p(buf); - return 0; } + runlock(&g->lock); - return -1; + return done ? -1 : 0; } int @@ -334,14 +360,20 @@ proptreegen(int n, Dir *d, void *aux) d->gid = estrdup9p(username); d->muid = estrdup9p(username); - if(n >= g->nprops) - return -1; + int done; + + rlock(&g->lock); + done = n >= g->nprops; + + if(!done){ + PropSpec spec = propspecs[g->props[n].tag]; + d->mode = 0666; + d->name = estrdup9p(spec.name); + d->qid = g->props[n].qid; + } + runlock(&g->lock); - PropSpec spec = propspecs[g->props[n].tag]; - d->mode = 0666; - d->name = estrdup9p(spec.name); - d->qid = g->props[n].qid; - return 0; + return done ? -1 : 0; } void @@ -365,7 +397,9 @@ fsread(Req *r) readstr(r, "eveeent\n"); break; case Qtype: + rlock(&g->lock); snprint(buf, sizeof(buf), "%s\n", guispecs[g->type].name); + runlock(&g->lock); readstr(r, buf); break; case Qprops: @@ -1,16 +1,55 @@ #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(DBlack); + 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; } @@ -24,37 +63,129 @@ printcolour(PropVal p) } 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) + 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) { - for(int i = 0; i < g->nprops; i++) + PropVal *v = nil; + rlock(&g->lock); + for(int i = 0; i < g->nprops && v == nil; i++) if(g->props[i].tag == tag) - return g->props[i].val; - sysfatal("invalid prop for this gui element"); + 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){ + if(g->props[i].tag == tag) g->props[i].val = val; - updategui(0); - return; - } + wunlock(&g->lock); + updategui(0); } PropSpec propspecs[Pmax] = { [Pbackground] = {"background", defbackground, printcolour, parsecolour}, -};
\ No newline at end of file + [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};
\ No newline at end of file @@ -2,25 +2,49 @@ rfork n +delay=0.25 + guifs -s testgui dir=/mnt/gui -sleep 1 +sleep $delay -colours=(FF0000 00FF00 0000FF FFFF00 00FFFF FF00FF FFFFFF) +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" with a small margin) + 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 - sleep 1 # Wait a bit + sleep $delay # Wait a bit } # Now do the same, but don't nest the elements for(colour in $colours){ subdir=$dir/`{cat $dir/clone} echo $colour^FF >> $subdir/props/background - sleep 1 + sleep $delay +} + +# Add some padding to all elements +for(f in `{walk /mnt/gui/ | grep 'padding$'}){ + echo 10 >> $f + sleep $delay +} + +# Add a border to the innermost elements +for(f in `{walk /mnt/gui | grep $dir'/[0-9]+/props/border$'}){ + echo 8888CCFF >> $f^colour + echo 5 >> $f + sleep $delay +} + +# Add some margin to the innermost elements +for(f in `{walk /mnt/gui | grep $dir'/[0-9]+/props/margin'}){ + echo 5 >> $f + sleep $delay } -# when the script ends, the old text window draws over the gui :joyd: I will fix that later. +# Make the inner container vertical +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 sleep 1000000 |