ref: 0adb432869b58347d874cd8961584817cd478c26
dir: /scrolldemo/scrolldemo.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 "../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);
}