ref: df830dd2a611299eda94cadaf6e2d08a81ec2a59
dir: /text.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <frame.h>
#include "mez.h"
enum {
Scrollwid = 12, /* width of scroll bar */
Scrollgap = 4, /* gap right of scroll bar */
Margin = 4, /* margin around text */
};
#define max(a, b) ((a)>(b)?(a):(b))
#define min(a, b) ((a)<(b)?(a):(b))
void
textdraw(Text *t)
{
Rectangle scrpos;
Image *screen;
screen = *t->screen;
draw(screen, screen->r, t->cols[BACK], nil, ZP);
draw(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)
{
Image *screen;
screen = *t->screen;
t->scrollr = screen->r;
t->scrollr.max.x = screen->r.min.x + Scrollwid + 1;
t->bodyr.min.x = screen->r.min.x + Scrollwid + Scrollgap + Margin;
t->bodyr.min.y = screen->r.min.y;
t->bodyr.max = screen->r.max;
if(t->text == nil){
t->textcap = 8192;
t->text = emallocz(t->textcap*sizeof(*t->text), 1);
t->textlen = 0;
}
if(t->lines == nil){
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, screen, t->cols);
}
void
textaddline(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
textaddrunes(Text *t, Rune *s)
{
Rune *rp;
int len;
len = runestrlen(s);
while(len > t->textcap-t->textlen+1){
t->textcap *= 2;
t->text = erealloc(t->text, t->textcap*sizeof(*t->text));
}
runestrecpy(t->text+t->textlen, t->text+t->textcap, s);
for(rp = t->text+t->textlen; *rp != L'\0'; rp++)
if(*rp == L'\n') textaddline(t, rp+1-t->text);
t->textlen += len;
}
void
textresize(Text *t)
{
static char s[512];
snprint(s, sizeof(s), "%s/winname", t->wsys);
if(gengetwindow(display, s, t->screen, t->_screen, Refnone) < 0)
sysfatal("%s: %r", argv0);
textinit(t);
textdraw(t);
}
void
textscroll(Text *t, Mousectl *mc)
{
uint pos, i;
while(mc->buttons == 2){
t->topline = min(max(0, mc->xy.y-t->scrollr.min.y)*t->nlines/Dy(t->scrollr), t->nlines-1);
textdraw(t);
readmouse(mc);
}
while(mc->buttons == 1){
pos = frcharofpt(t, (Point){t->bodyr.min.x+1, mc->xy.y});
for(i = t->topline; t->lines[t->topline]+pos > t->lines[i]; i++){
if(i == t->nlines) break;
}
i -= t->topline;
if(t->topline < i) t->topline = 0;
else t->topline -= i;
textdraw(t);
readmouse(mc);
}
while(mc->buttons == 4){
pos = frcharofpt(t, (Point){t->bodyr.min.x+1, mc->xy.y});
for(i = t->topline; t->lines[t->topline]+pos > t->lines[i]; i++);
t->topline = min(i, t->nlines-1);
textdraw(t);
readmouse(mc);
}
}
void
textmouse(Text *t, Mousectl *mc)
{
if(ptinrect(mc->xy, t->scrollr)){
textscroll(t, mc);
return;
}
}