ref: a959605dff6d7ffffbca9441db4e57b98b261b71
dir: /guitest.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <cursor.h> #include <thread.h> #include <mouse.h> #include <keyboard.h> #include <frame.h> #include "mez.h" Image *nicksscreen, *cmdscreen, *nickscols[NCOL], *cols[NCOL], *cmdcols[NCOL]; char *nickswsys = "/mnt/nickswsys", *cmdwsys = "/mnt/cmdwsys"; Screen *_nicksscreen, *_cmdscreen; char buf[32000]; Rune lorem[32000]; enum { MOUSE, KEYBD, RESIZE, NICKSMOUSE, NICKSKEYBD, NICKSRESIZE, CMDMOUSE, CMDKEYBD, CMDRESIZE, NCHAN, Scrollwid = 12, /* width of scroll bar */ Scrollgap = 4, /* gap right of scroll bar */ Margin = 4, /* margin around text */ }; void error(char *s) { fprint(2, "%s: error: %s: %r\n", argv0, s); threadexits(s); } void* emallocz(ulong sz, int clr) { void *p; if((p = mallocz(sz, clr)) == nil) error("Out of memory here"); setmalloctag(p, getcallerpc(&sz)); return p; } void* erealloc(void *ptr, ulong size) { void *p; if((p = realloc(ptr, size)) == nil) error("Out of memory there"); setmalloctag(p, getcallerpc(&ptr)); return p; } uint lines(Rune *text) { Rune *e; uint l; e = text; for(l = 0; e != nil; l++) e = runestrchr(e+1, L'\n'); return l; } #define max(a, b) ((a)>(b)?(a):(b)) #define min(a, b) ((a)<(b)?(a):(b)) void textdraw(Text *t) { Rectangle scrpos; Image *screen; screen = *t->screen; draw(screen, screen->r, t->cols[BACK], nil, ZP); draw(screen, t->scrollr, t->cols[BORD], nil, ZP); scrpos = t->scrollr; if(t->nlines > 0){ scrpos.min.y = scrpos.min.y+max(0, Dy(scrpos))*t->origin/t->nlines; scrpos.max.y = scrpos.min.y+Dy(t->scrollr)*t->Frame.maxlines/t->nlines; } scrpos = insetrect(scrpos, 1); draw(screen, scrpos, t->cols[BACK], nil, ZP); frinsert(t, t->text+t->lines[t->origin], t->text+t->textlen, 0); flushimage(display, 1); } void textinit(Text *t) { Image *screen; screen = *t->screen; t->scrollr = screen->r; t->scrollr.max.x = screen->r.min.x + Scrollwid + 1; t->bodyr.min.x = screen->r.min.x + Scrollwid + Scrollgap + Margin; t->bodyr.min.y = screen->r.min.y; t->bodyr.max = screen->r.max; if(t->text == nil){ t->textcap = 8192; t->text = emallocz(t->textcap*sizeof(*t->text), 1); t->textlen = 0; } if(t->lines == nil){ t->linescap = 1024; t->lines = emallocz(t->linescap*sizeof(*t->lines), 1); t->nlines = 0; t->origin = 0; } frclear(t, 0); frinit(t, t->bodyr, display->defaultfont, screen, t->cols); } void createwindow(char *wsys, Image **screen, Screen **_screen, Rectangle r) { static char s[512]; char *wsysv; int fd; if((wsysv = getenv("wsys")) == nil) sysfatal("cannot find $wsys: %r"); if((fd = open(wsysv, ORDWR)) < 0) sysfatal("cannot open $wsys: %r"); free(wsysv); snprint(s, sizeof(s), "new -r %d %d %d %d", r.min.x, r.min.y, r.max.x, r.max.y); if(mount(fd, -1, wsys, MREPL, s) < 0) sysfatal("cannot create new window: %r"); close(fd); snprint(s, sizeof(s), "%s/label", wsys); if((fd = open(s, OWRITE)) < 0) sysfatal("cannot open label: %r"); write(fd, "guitest", sizeof("guitest")); close(fd); snprint(s, sizeof(s), "%s/winname", wsys); if(gengetwindow(display, s, screen, _screen, Refnone) < 0) sysfatal("cannot get window: %r"); } void textsetline(Text *t, uint sol) { if(t->nlines == t->linescap){ t->linescap *= 2; t->lines = erealloc(t->lines, t->linescap*sizeof(*t->lines)); } t->lines[t->nlines++] = sol; } void textaddlines(Text *t, Rune *s) { Rune *rp; uint sol; int len; len = runestrlen(s); while(len > t->textcap-t->textlen+1){ t->textcap *= 2; t->text = erealloc(t->text, t->textcap*sizeof(*t->text)); } runestrecpy(t->text+t->textlen, t->text+t->textcap, s); sol = t->textlen; for(rp = s; rp = runestrchr(rp, L'\n'); rp++){ textsetline(t, sol); sol = rp + 1 - s + t->textlen; } t->textlen += len; } void textresize(Text *t) { static char s[512]; snprint(s, sizeof(s), "%s/winname", t->wsys); if(gengetwindow(display, s, t->screen, t->_screen, Refnone) < 0) sysfatal("%s: %r", argv0); textinit(t); textdraw(t); } void textscroll(Text *t, Mousectl *mc) { uint pos, i, diff; while(mc->buttons == 2){ t->origin = min(max(0, mc->xy.y-t->scrollr.min.y)*t->nlines/Dy(t->scrollr), t->nlines-1); textdraw(t); readmouse(mc); } while(mc->buttons == 1){ pos = frcharofpt(t, (Point){t->bodyr.min.x+1, mc->xy.y}); for(i = t->origin; t->lines[t->origin]+pos > t->lines[i]; i++); t->origin -= i-t->origin; textdraw(t); readmouse(mc); } while(mc->buttons == 4){ pos = frcharofpt(t, (Point){t->bodyr.min.x+1, mc->xy.y}); for(i = t->origin; t->lines[t->origin]+pos > t->lines[i]; i++); t->origin = min(i, t->nlines-1); textdraw(t); readmouse(mc); } } void textmouse(Text *t, Mousectl *mc) { if(ptinrect(mc->xy, t->scrollr)){ textscroll(t, mc); return; } } void initmousekbd(char *wsys, Image *screen, Mousectl **mc, Keyboardctl **kc) { static char s[512]; snprint(s, sizeof(s), "%s/mouse", wsys); if((*mc = initmouse(s, screen)) == nil) sysfatal("initmouse failed: %r"); snprint(s, sizeof(s), "%s/cons", wsys); if((*kc = initkeyboard(s)) == nil) sysfatal("initkeyboard failed: %r"); } void threadmain(int argc, char **argv) { Chan *chan; Keyboardctl *kc, *nickskc, *cmdkc; Mousectl *mc, *nicksmc, *cmdmc; Rune r, *rs; Rectangle dim; Text *cmd; char *s, *nicksf; int len, fd; nicksf = nil; ARGBEGIN{ default: sysfatal("foo"); case 'n': nicksf = EARGF(sysfatal("foo")); break; }ARGEND len = readn(0, buf, sizeof(buf)); buf[len] = '\0'; for(s = buf, rs = lorem; *s != '\0'; s+=len, rs++) len = chartorune(rs, s); *rs = L'\0'; if(initdraw(nil, nil, "guitest") < 0) sysfatal("initdraw: %r"); cols[BACK] = allocimagemix(display, DPurpleblue, DWhite); cols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow); cols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue); cols[TEXT] = display->black; cols[HTEXT] = display->black; nickscols[BACK] = allocimagemix(display, DCyan, DWhite); nickscols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow); nickscols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue); nickscols[TEXT] = display->black; nickscols[HTEXT] = display->black; cmdcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite); cmdcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen); cmdcols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DPurpleblue); cmdcols[TEXT] = display->black; cmdcols[HTEXT] = display->black; chan = emallocz(sizeof(*chan), 1); memmove(chan->body.cols, cols, sizeof(cols)); chan->body.screen = &screen; chan->body._screen = &_screen; chan->body.wsys = "/dev"; textinit(&chan->body); textaddlines(&chan->body, lorem); lorem[0] = L'\0'; if(nicksf != nil){ if((fd = open(nicksf, OREAD)) < 0) sysfatal("Could not open nicks file"); len = readn(fd, buf, sizeof(buf)); close(fd); buf[len] = '\0'; for(s = buf, rs = lorem; *s != '\0'; s+=len, rs++) len = chartorune(rs, s); *rs = L'\0'; } dim = (Rectangle){ (Point){screen->r.min.x - Dx(screen->r)/3, screen->r.min.y-4}, (Point){screen->r.min.x-4, screen->r.max.y+4} }; createwindow(nickswsys, &nicksscreen, &_nicksscreen, dim); memmove(chan->nicks.cols, nickscols, sizeof(nickscols)); chan->nicks.screen = &nicksscreen; chan->nicks._screen = &_nicksscreen; chan->nicks.wsys = nickswsys; textinit(&chan->nicks); textaddlines(&chan->nicks, lorem); cmd = emallocz(sizeof(*cmd), 1); dim = (Rectangle){ (Point){screen->r.min.x - Dx(screen->r)/3, screen->r.min.y-Dy(screen->r)/4}, (Point){screen->r.max.x+4, screen->r.min.y-4} }; createwindow(cmdwsys, &cmdscreen, &_cmdscreen, dim); memmove(cmd->cols, cmdcols, sizeof(cmdcols)); cmd->screen = &cmdscreen; cmd->_screen = &_cmdscreen; cmd->wsys = cmdwsys; textinit(cmd); textdraw(&chan->body); textdraw(&chan->nicks); textdraw(cmd); flushimage(display, 1); initmousekbd("/dev", screen, &mc, &kc); initmousekbd(nickswsys, nicksscreen, &nicksmc, &nickskc); initmousekbd(cmdwsys, cmdscreen, &cmdmc, &cmdkc); Alt a[NCHAN+1] = { [MOUSE] {mc->c, nil, CHANRCV}, [KEYBD] {kc->c, &r, CHANRCV}, [RESIZE] {mc->resizec, nil, CHANRCV}, [NICKSMOUSE] {nicksmc->c, nil, CHANRCV}, [NICKSKEYBD] {nickskc->c, &r, CHANRCV}, [NICKSRESIZE] {nicksmc->resizec, nil, CHANRCV}, [CMDMOUSE] {cmdmc->c, nil, CHANRCV}, [CMDKEYBD] {cmdkc->c, &r, CHANRCV}, [CMDRESIZE] {cmdmc->resizec, nil, CHANRCV}, [NCHAN] {nil, nil, CHANEND}, }; for(;;)switch(alt(a)){ default: break; case NICKSKEYBD: case CMDKEYBD: case KEYBD: if(r == Kdel) goto end; break; case MOUSE: textmouse(&chan->body, mc); break; case NICKSMOUSE: textmouse(&chan->nicks, nicksmc); break; case CMDMOUSE: textmouse(cmd, cmdmc); break; case RESIZE: textresize(&chan->body); break; case NICKSRESIZE: textresize(&chan->nicks); break; case CMDRESIZE: textresize(cmd); break; } end: unmount(nil, nickswsys); unmount(nil, cmdwsys); threadexitsall(0); }