shithub: libscroll

Download patch

ref: 25bcd2fab4c8c6bdc15f72140c966612a2409c44
parent: c61a6b9909e6a2b16ac76a137bfb29c9a919c339
author: spew <spew@palas>
date: Wed Feb 19 23:40:59 EST 2025

make a demo to see how poorly this works

--- a/scroll.c
+++ b/scroll.c
@@ -78,8 +78,8 @@
 	case 1:
 	case 8:
 		p₀ = (s->p₁-s->p₀)*(y-s->r.min.y)/h+s->p₀;
-		if(2*s->p₀ > p₀)
-			p₀ = 2*s->p₀-p₀;
+		if(s->p₀ > p₀-s->p₀)
+			p₀ = s->p₀-p₀+s->p₀;
 		else
 			p₀ = 0;
 		break;
--- /dev/null
+++ b/scrolldemo/mkfile
@@ -1,0 +1,9 @@
+</$objtype/mkfile
+
+TARG=scrolldemo
+BIN=/$objtype/bin
+LIB=../libscroll.$O.a
+OFILES=scrolldemo.$O
+HFILES=../scroll.h
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/scrolldemo/scrolldemo.c
@@ -1,0 +1,177 @@
+#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);
+}