shithub: libscroll

ref: 0adb432869b58347d874cd8961584817cd478c26
dir: /scrolldemo/scrolldemo.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 "../scroll.h"

typedef struct Text Text;
struct Text {
	Frame;
	Scroll;
	Rune *text;
	uint org, len, cap;
};

Image *cols[NCOL];
char buf[32000];
Rune lorem[32000];

enum
{
	MOUSE,
	KEYBD,
	RESIZE,
	NCHAN,
};

void
textdraw(Text *t)
{
	draw(screen, screen->r, cols[BACK], nil, ZP);
	frinsert(t, t->text+t->org, t->text+t->len, 0);
	scrollpos(t, t->org, t->org+t->Frame.nchars, t->len);
	flushimage(display, 1);
}

void
textinit(Text *t)
{
	Rectangle r;

	if(t->text == nil){
		t->cap = 8192;
		t->text = mallocz(t->cap*sizeof(*t->text), 1);
		t->len = 0;
	}
	r = scrollinit(t, screen->r, screen, cols);
	frclear(t, 0);
	frinit(t, r, display->defaultfont, screen, cols);
}

void
textaddrunes(Text *t, Rune *s)
{
	int len;

	len = runestrlen(s);
	while(len > t->cap-t->len+1){
		t->cap *= 2;
		t->text = realloc(t->text, t->cap*sizeof(*t->text));
	}
	runestrecpy(t->text+t->len, t->text+t->cap, s);
	t->len += len;
}

void
textresize(Text *t)
{
	static char s[512];

	if(getwindow(display, Refnone) < 0)
		sysfatal("%s: %r", argv0);
	textinit(t);
	textdraw(t);
}

uint
bol(Text *t, uint org)
{
	for(;org > 0; org--){
		if(t->text[org-1] == L'\n')
			return org;
	}
	return org;
}

void
textscroll(Text *t, Mousectl *mc)
{
	while(mc->buttons == 2){
		t->org = bol(t, scrollscr(t, mc));
		textdraw(t);
		readmouse(mc);
	}
	if(mc->buttons == 1 || mc->buttons == 8 || mc->buttons == 4 || mc->buttons == 16){
		t->org = bol(t, scrollscr(t, mc));
		textdraw(t);
	}
}

void
textmouse(Text *t, Mousectl *mc)
{
	if(scrollactive(t, mc))
		textscroll(t, mc);
}

void
threadmain(int argc, char **argv)
{
	Text *text;
	Keyboardctl *kc;
	Mousectl *mc;
	Rune r, *rs;
	char *s;
	int len;

	ARGBEGIN{
	default:
		sysfatal("foo");
	}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;

	text = mallocz(sizeof(*text), 1);

	textinit(text);
	textaddrunes(text, lorem);
	lorem[0] = L'\0';

	textdraw(text);
	flushimage(display, 1);

	if((mc = initmouse(nil, screen)) == nil)
		sysfatal("initmouse failed: %r");
	if((kc = initkeyboard(nil)) == nil)
		sysfatal("initkeyboard failed: %r");

	Alt a[NCHAN+1] = {
		[MOUSE] {mc->c, nil, CHANRCV},
		[KEYBD] {kc->c, &r, CHANRCV},
		[RESIZE] {mc->resizec, nil, CHANRCV},
		[NCHAN] {nil, nil, CHANEND},
	};
	for(;;)switch(alt(a)){
	default:
		break;
	case KEYBD:
		if(r == Kdel)
			goto End;
		break;
	case MOUSE:
		textmouse(text, mc);
		break;
	case RESIZE:
		textresize(text);
		break;
	}
End:
	threadexitsall(0);
}