From 2293ed78636e5f66b5e2884bebd193803cb6939f Mon Sep 17 00:00:00 2001 From: rodri Date: Fri, 22 Sep 2023 15:32:36 +0000 Subject: add parsecmd to the client. finish the menulist of matches. the menulist now supports scrolling. also changed some cursors and got to tidy up /^lmb\(. --- bts.c | 136 ++++++++++++++++++++++++++++++++++++++++--------------------- menulist.c | 68 +++++++++++++++++++++++++------ 2 files changed, 144 insertions(+), 60 deletions(-) diff --git a/bts.c b/bts.c index 361bc1c..cac8f22 100644 --- a/bts.c +++ b/bts.c @@ -9,6 +9,41 @@ #include "dat.h" #include "fns.h" +enum { + CMid, + CMqueued, + CMlayout, + CMoid, + CMwait, + CMplay, + CMwehit, + CMwemiss, + CMtheyhit, + CMtheymiss, + CMmatchesb, /* list header */ + CMmatch, /* list entry */ + CMmatchese, /* list tail */ + CMwin, + CMlose, +}; +Cmdtab svcmd[] = { + CMid, "id", 1, + CMqueued, "queued", 1, + CMlayout, "layout", 1, + CMoid, "oid", 2, + CMwait, "wait", 1, + CMplay, "play", 1, + CMwehit, "hit", 1, + CMwemiss, "miss", 1, + CMtheyhit, "hit", 2, + CMtheymiss, "miss", 2, + CMmatchesb, "matches", 1, + CMmatch, "m", 4, + CMmatchese, "end", 1, + CMwin, "win", 1, + CMlose, "lose", 1, +}; + int debug; Cursor patrolcursor = { @@ -174,7 +209,7 @@ resetgame(void) oid[0] = 0; game.state = Waiting0; conclusion.s = nil; - csetcursor(mctl, &patrolcursor); + csetcursor(mctl, nil); } Point @@ -498,36 +533,33 @@ confirmdone(Mousectl *mc) void lmb(Mousectl *mc) { - Board *b; Point2 cell; - b = nil; - if(ptinrect(mc->xy, alienboard.bbox)) - b = &alienboard; - else if(ptinrect(mc->xy, localboard.bbox)) - b = &localboard; - - if(b == nil || conclusion.s != nil) + if(conclusion.s != nil) return; - cell = toboard(b, mc->xy); switch(game.state){ case Outlaying: - if(b == &localboard) - if(curship != nil && rectinrect(curship->bbox, localboard.bbox)) - if(++curship-armada >= nelem(armada)) - curship = nil; - else if(curship != &armada[0]) - curship->orient = (curship-1)->orient; + if(!ptinrect(mc->xy, localboard.bbox)) + break; + + if(curship != nil && rectinrect(curship->bbox, localboard.bbox)){ + if(++curship-armada >= nelem(armada)) + curship = nil; + else if(curship != &armada[0]) + curship->orient = (curship-1)->orient; + nbsend(drawchan, nil); + } break; case Playing: - if(b == &alienboard){ - chanprint(egress, "shoot %s\n", cell2coords(cell)); - lastshot = cell; - } + if(!ptinrect(mc->xy, alienboard.bbox)) + break; + + cell = toboard(&alienboard, mc->xy); + chanprint(egress, "shoot %s\n", cell2coords(cell)); + lastshot = cell; break; } - nbsend(drawchan, nil); } void @@ -619,9 +651,14 @@ mouse(Mousectl *mc) { Rectangle newbbox; static Mouse oldm; + int selmatch; mc->xy = subpt(mc->xy, screen->r.min); + if(game.state == Waiting0) + if((selmatch = matches->update(matches, mc, drawchan)) >= 0) + if(debug) fprint(2, "selected match id %d title %s\n", selmatch, matches->entries[selmatch].title); + if(game.state == Outlaying && curship != nil){ newbbox = mkshipbbox(toboard(&localboard, mc->xy), curship->orient, curship->ncells); @@ -712,42 +749,47 @@ keelhaul(void) void processcmd(char *cmd) { + Cmdbuf *cb; + Cmdtab *ct; Point2 cell; - char *f[3]; - int i, nf; + int i; if(debug) fprint(2, "rcvd '%s'\n", cmd); - nf = tokenize(cmd, f, nelem(f)); - if(nf < 1) + cb = parsecmd(cmd, strlen(cmd)); + ct = lookupcmd(cb, svcmd, nelem(svcmd)); + if(ct == nil){ + free(cb); return; + } - if(nf == 1 && strcmp(f[0], "win") == 0) + if(ct->index == CMwin) celebrate(); - else if(nf == 1 && strcmp(f[0], "lose") == 0) + else if(ct->index == CMlose) keelhaul(); switch(game.state){ case Waiting0: - if(nf == 1 && strcmp(f[0], "id") == 0) + if(ct->index == CMid) chanprint(egress, "id %s\n", uid); - else if(nf == 1 && strcmp(f[0], "queued") == 0) + else if(ct->index == CMqueued){ game.state = Ready; - else if(!matches->filling && nf == 1 && strcmp(f[0], "matches") == 0){ + csetcursor(mctl, &patrolcursor); + }else if(!matches->filling && ct->index == CMmatchesb){ matches->clear(matches); matches->filling = 1; - }else if(matches->filling && nf == 3) - matches->add(matches, strtoul(f[0], nil, 10), smprint("%s vs %s", f[1], f[2])); - else if(matches->filling && nf == 1 && strcmp(f[0], "end") == 0) + }else if(matches->filling && ct->index == CMmatch) + matches->add(matches, strtoul(cb->f[1], nil, 10), smprint("%s vs %s", cb->f[2], cb->f[3])); + else if(matches->filling && ct->index == CMmatchese) matches->filling = 0; break; case Ready: - if(nf == 1 && strcmp(f[0], "layout") == 0){ + if(ct->index == CMlayout){ game.state = Outlaying; curship = &armada[0]; - }else if(nf == 2 && strcmp(f[0], "oid") == 0) - snprint(oid, sizeof oid, "%s", f[1]); + }else if(ct->index == CMoid) + snprint(oid, sizeof oid, "%s", cb->f[1]); break; case Watching: /* (hit|missed) */ @@ -756,39 +798,40 @@ processcmd(char *cmd) */ break; case Outlaying: - if(nf == 1 && strcmp(f[0], "wait") == 0){ + if(ct->index == CMwait){ game.state = Waiting; csetcursor(mctl, &waitcursor); - }else if(nf == 1 && strcmp(f[0], "play") == 0) + }else if(ct->index == CMplay) game.state = Playing; break; case Playing: - if(nf == 1 && strcmp(f[0], "wait") == 0){ + if(ct->index == CMwait){ game.state = Waiting; csetcursor(mctl, &waitcursor); - }else if(nf == 1 && strcmp(f[0], "hit") == 0) + }else if(ct->index == CMwehit) settile(&alienboard, lastshot, Thit); - else if(nf == 1 && strcmp(f[0], "miss") == 0) + else if(ct->index == CMwemiss) settile(&alienboard, lastshot, Tmiss); break; case Waiting: - if(nf == 1 && strcmp(f[0], "play") == 0){ + if(ct->index == CMplay){ game.state = Playing; csetcursor(mctl, nil); - }else if(nf == 2 && strcmp(f[0], "hit") == 0){ - cell = coords2cell(f[1]); + }else if(ct->index == CMtheyhit){ + cell = coords2cell(cb->f[1]); for(i = 0; i < nelem(armada); i++) if(ptinrect(fromboard(&localboard, cell), armada[i].bbox)){ cell = subpt2(cell, armada[i].p); armada[i].hit[(int)vec2len(cell)] = 1; break; } - }else if(nf == 2 && strcmp(f[0], "miss") == 0){ - cell = coords2cell(f[1]); + }else if(ct->index == CMtheymiss){ + cell = coords2cell(cb->f[1]); settile(&localboard, cell, Tmiss); } break; } + free(cb); nbsend(drawchan, nil); } @@ -906,7 +949,6 @@ threadmain(int argc, char *argv[]) initarmada(); matches = newmenulist(14*font->height, "ongoing matches"); game.state = Waiting0; - csetcursor(mctl, &patrolcursor); drawchan = chancreate(sizeof(void*), 1); ingress = chancreate(sizeof(char*), 1); diff --git a/menulist.c b/menulist.c index 8cd41a8..52b5362 100644 --- a/menulist.c +++ b/menulist.c @@ -13,7 +13,7 @@ enum { Menuborder = 2, Vspace = 2, Scrollwidth = 10, - Maxvisitems = 5, + Maxvisitems = 8, }; static char none[] = "none"; @@ -31,7 +31,11 @@ menulist_add(Menulist *ml, int id, char *title) ml->r.min.x = SCRW/2 - ew/2; ml->r.max.x = ml->r.min.x + ew; } - if(ml->nentries > 1) + + if(ml->nentries > Maxvisitems){ + ml->sr.min = subpt(ml->r.min, Pt(Scrollwidth+2*Menuborder,0)); + ml->sr.max = Pt(ml->r.min.x-2*Menuborder, ml->r.max.y); + }else if(ml->nentries > 1) ml->r.max.y += font->height+Vspace; } @@ -55,16 +59,45 @@ menulist_clear(Menulist *ml) ml->r.max = addpt(ml->r.min, Pt(w, font->height+Vspace)); ml->sr = ZR; ml->high = -1; + ml->off = 0; } -static void -menulist_update(Menulist *ml, Mousectl *mc) +static int +menulist_update(Menulist *ml, Mousectl *mc, Channel *drawchan) { - if(ptinrect(mc->xy, ml->r)){ - /* item highlighting and selection */ - }else if(ptinrect(mc->xy, ml->sr)){ - /* scrolling */ + /* redundant from bts.c:/^mouse\(, but it's necessary to avoid overdrawing */ + static Mouse oldm; + static ulong lastlmbms; + int selected; + + selected = -1; + if(ptinrect(mc->xy, Rpt(ml->sr.min, ml->r.max))){ + if(ptinrect(mc->xy, ml->r)){ + /* item highlighting and selection */ + ml->high = ml->off + (mc->xy.y - ml->r.min.y)/(font->height+Vspace); + if(oldm.buttons != mc->buttons && mc->buttons == 1){ + if(mc->msec-lastlmbms < 500) + selected = ml->high; + else + lastlmbms = mc->msec; + } + } + if(mc->buttons != oldm.buttons && ml->nentries > Maxvisitems) + /* scrolling */ + switch(mc->buttons){ + case 1: if(!ptinrect(mc->xy, ml->sr)) break; + case 8: + ml->off = max(0, ml->off - (mc->xy.y - ml->sr.min.y)/(font->height+Vspace)); + break; + case 4: if(!ptinrect(mc->xy, ml->sr)) break; + case 16: + ml->off = min(ml->off + (mc->xy.y - ml->sr.min.y)/(font->height+Vspace), ml->nentries-Maxvisitems); + break; + } } + nbsendp(drawchan, nil); + oldm = mc->Mouse; + return selected; } static void @@ -72,7 +105,7 @@ menulist_draw(Menulist *ml, Image *dst) { static Image *bc; Rectangle tr, er; /* title and per-entry */ - int i; + int i, width; if(ml->filling) return; @@ -81,18 +114,20 @@ menulist_draw(Menulist *ml, Image *dst) bc = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue); /* draw title */ + width = stringwidth(font, ml->title); tr.min = subpt(ml->r.min, Pt(0,Menuborder + font->height+Vspace)); tr.max = Pt(ml->r.max.x, ml->r.min.y - Menuborder); draw(dst, tr, display->black, nil, ZP); - string(dst, tr.min, display->white, ZP, font, ml->title); + string(dst, addpt(tr.min, Pt(Dx(tr)/2 - width/2,0)), display->white, ZP, font, ml->title); /* draw content */ border(dst, ml->r, -Menuborder, bc, ZP); er.min = ml->r.min; er.max = Pt(ml->r.max.x, er.min.y + font->height+Vspace); - for(i = 0; i < ml->nentries; i++){ - draw(dst, er, display->white, nil, ZP); - string(dst, er.min, display->black, ZP, font, ml->entries[i].title); + for(i = ml->off; i < ml->nentries && er.min.y < ml->r.max.y; i++){ + width = stringwidth(font, ml->entries[i].title); + draw(dst, er, i == ml->high? display->black: display->white, nil, ZP); + string(dst, addpt(er.min, Pt(Dx(er)/2 - width/2,0)), i == ml->high? display->white: display->black, ZP, font, ml->entries[i].title); er.min.y += font->height+Vspace; er.max.y = er.min.y + font->height+Vspace; } @@ -100,6 +135,13 @@ menulist_draw(Menulist *ml, Image *dst) draw(dst, er, display->white, nil, ZP); string(dst, er.min, display->black, ZP, font, none); } + + /* draw scroll */ + if(ml->nentries > Maxvisitems){ + border(dst, ml->sr, -Menuborder, bc, ZP); + draw(dst, ml->sr, display->black, nil, ZP); + draw(dst, Rpt(addpt(ml->sr.min, Pt(0,ml->off*Dy(ml->sr)/ml->nentries)), Pt(ml->sr.max.x,ml->sr.min.y + (ml->off+Maxvisitems)*Dy(ml->sr)/ml->nentries)), display->white, nil, ZP); + } } Menulist * -- cgit v1.2.3