ref: c9133834024f6fd08a9c0410f67885c2382427ec
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; Image *cols[NCOL], *cmdcols[NCOL]; char buf[8192]; Rune lorem[8192]; 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; } 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)) Rune* offset(Rune *origin, int line) { int i; Rune *r; r = origin; for(i = 0; i < line; i++){ origin = runestrchr(r, L'\n'); if(origin == nil) break; r = origin+1; } return r; } Rectangle scrollr; void drawtext(Chan *chan, int resize) { Rectangle scrollcur, bodyr; scrollr = screen->r; scrollr.max.x = screen->r.min.x + Scrollwid + 1; bodyr.min.x = screen->r.min.x + Scrollwid + Scrollgap + Margin; bodyr.min.y = screen->r.min.y; bodyr.max = screen->r.max; if(resize){ frclear(chan, 0); frinit(chan, bodyr, display->defaultfont, screen, cols); } draw(screen, screen->r, cols[BACK], nil, ZP); frinsert(chan, offset(chan->body, chan->curline), chan->body + chan->bodylen, 0); draw(screen, scrollr, cols[BORD], nil, ZP); scrollcur = scrollr; scrollcur.min.y = screen->r.min.y + max(0, Dy(screen->r)*chan->curline/chan->totlines); scrollcur.max.y = scrollcur.min.y+Dy(screen->r)*chan->maxlines/chan->totlines; scrollcur = insetrect(scrollcur, 1); draw(screen, scrollcur, cols[BACK], nil, ZP); flushimage(display, 1); } void setcurline(int y, Chan *chan) { chan->curline = (y-scrollr.min.y)*chan->totlines/Dy(scrollr); } void threadmain(int argc, char **argv) { Rune r, *rs; Mouse m; Chan *chan; char *s; int len; len = readn(0, buf, sizeof(buf)); buf[len] = '\0'; for(s = buf, rs = lorem; *s != '\0'; s+=len, rs++) len = chartorune(rs, s); 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"); 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; chan = emallocz(sizeof(*chan), 1); chan->body = lorem; chan->bodylen = runestrlen(chan->body); chan->totlines = lines(chan->body); Alt a[NCHAN+1] = { [MOUSE] = {mc->c, &m, CHANRCV}, [RESIZE] = {mc->resizec, nil, CHANRCV}, [KEYBD] = {kc->c, &r, CHANRCV}, [NCHAN] = {nil, nil, CHANEND}, }; drawtext(chan, 1); for(;;){ switch(alt(a)){ default: break; case KEYBD: if(r == Kdel) goto end; break; case MOUSE: if(!ptinrect(m.xy, scrollr)) break; while(m.buttons == 2){ setcurline(m.xy.y, chan); drawtext(chan, 0); readmouse(mc); m = *mc; } break; case RESIZE: if(getwindow(display, Refnone) < 0) sysfatal("%s: %r", argv0); drawtext(chan, 1); break; } } end: threadexitsall(0); }