shithub: mez

ref: 50aa3d1310d678ed8ff37791240c48d6c5045f65
dir: /guitest.c/

View raw version
#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, Image *screen)
{
	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, *wsys;
	int len, fd;
	Screen *_screennicks;
	Image *screennicks;

	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);

	if((wsys = getenv("wsys")) == nil)
		sysfatal("cannot find $wsys: %r");
	if((fd = open(wsys, ORDWR)) < 0)
		sysfatal("cannot open $wsys: %r");
	if(mount(fd, -1, "/mnt/wsysnicks", MREPL, "new") < 0)
		sysfatal("cannot create new window: %r");
	screennicks = nil;
	_screennicks = nil;
	if(gengetwindow(display, "/mnt/wsysnicks/winname", &screennicks, &_screennicks, 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},
	};
	drawtext(chan, 1, screen);
	draw(screennicks, screennicks->r, cols[BACK], 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, scrollr))
			break;
		while(m.buttons == 2){
			setcurline(m.xy.y, chan);
			drawtext(chan, 0, screen);
			readmouse(mc);
			m = *mc;
		}
		break;
	case RESIZE:
		if(getwindow(display, Refnone) < 0)
			sysfatal("%s: %r", argv0);
		drawtext(chan, 1, screen);
		break;
	}
end:
	unmount(nil, "/mnt/wsysnicks");
	threadexitsall(0);
}