ref: 1be7f16d6216762401da82b50a1b1606f5ac9667
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" Mousectl *mc; Keyboardctl *kc; char buf[32000]; Rune lorem[32000]; enum { MOUSE, KEYBD, RESIZE, 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"); setmalloctag(p, getcallerpc(&sz)); return p; } void* erealloc(void *ptr, ulong size) { void *p; if((p = realloc(ptr, size)) == nil) error("Out of memory"); 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; draw(t->screen, t->screen->r, t->cols[BACK], nil, ZP); draw(t->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->topline/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->topline], t->text + t->textlen, 0); flushimage(display, 1); } void textinit(Text *t) { t->scrollr = t->screen->r; t->scrollr.max.x = t->screen->r.min.x + Scrollwid + 1; t->bodyr.min.x = t->screen->r.min.x + Scrollwid + Scrollgap + Margin; t->bodyr.min.y = t->screen->r.min.y; t->bodyr.max = t->screen->r.max; t->text = emallocz(8192*sizeof(*t->text), 1); t->textcap = 8192; t->textlen = 0; t->linescap = 1024; t->lines = emallocz(t->linescap*sizeof(*t->lines), 1); t->nlines = 0; t->topline = 0; frclear(t, 0); frinit(t, t->bodyr, display->defaultfont, t->screen, t->cols); } 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-1 > t->textcap-t->textlen){ 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 texttopline(Text *t, int y) { t->topline = min(max(0, y-t->scrollr.min.y)*t->nlines/Dy(t->scrollr), t->nlines-1); } void threadmain(int argc, char **argv) { Rune r, *rs; Mouse m; Chan *chan; char *s, *wsys, *mntstr; int len, fd; ARGBEGIN{}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"); if((mc = initmouse(nil, screen)) == nil) sysfatal("initmouse failed: %r"); if((kc = initkeyboard(nil)) == nil) sysfatal("initmouse failed: %r"); chan = emallocz(sizeof(*chan), 1); chan->body.cols[BACK] = allocimagemix(display, DPurpleblue, DWhite); chan->body.cols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow); chan->body.cols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue); chan->body.cols[TEXT] = display->black; chan->body.cols[HTEXT] = display->black; chan->body.screen = screen; textinit(&chan->body); textaddlines(&chan->body, lorem); if((wsys = getenv("wsys")) == nil) sysfatal("cannot find $wsys: %r"); if((fd = open(wsys, ORDWR)) < 0) sysfatal("cannot open $wsys: %r"); mntstr = smprint("new -r %d %d %d %d", screen->r.min.x - Dx(screen->r)/3, screen->r.min.y-4, screen->r.min.x-4, screen->r.max.y+4); if(mount(fd, -1, "/mnt/wsysnicks", MREPL, mntstr) < 0) sysfatal("cannot create new window: %r"); if(gengetwindow(display, "/mnt/wsysnicks/winname", &chan->nicks.screen, &chan->nicks._screen, Refnone) < 0) sysfatal("cannot get window: %r"); Alt a[NCHAN+1] = { [MOUSE] = {mc->c, &m, CHANRCV}, [RESIZE] = {mc->resizec, nil, CHANRCV}, [KEYBD] = {kc->c, &r, CHANRCV}, [NCHAN] = {nil, nil, CHANEND}, }; textdraw(&chan->body); draw(chan->nicks.screen, chan->nicks.screen->r, chan->body.cols[HIGH], nil, ZP); flushimage(display, 1); for(;;)switch(alt(a)){ default: break; case KEYBD: if(r == Kdel) goto end; break; case MOUSE: if(!ptinrect(m.xy, chan->body.scrollr)) break; while(m.buttons == 2){ texttopline(&chan->body, m.xy.y); textdraw(&chan->body); readmouse(mc); m = *mc; } break; case RESIZE: if(getwindow(display, Refnone) < 0) sysfatal("%s: %r", argv0); textinit(&chan->body); textdraw(&chan->body); break; } end: unmount(nil, "/mnt/wsysnicks"); threadexitsall(0); }