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