ref: 0adb432869b58347d874cd8961584817cd478c26
parent: 25bcd2fab4c8c6bdc15f72140c966612a2409c44
author: spew <spew@palas>
date: Fri Feb 21 19:23:00 EST 2025
add another demo
--- /dev/null
+++ b/scrolldemo/demolines.c
@@ -1,0 +1,180 @@
+/* This example measures distance in lines which results in
+ * more accurate scrolling. The values of p₀, p₁ and tot passed
+ * to scrollpos are in lines. This is to demonstrate that the
+ * caller can choose their own units for the scroll functions.
+ */
+
+#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, line, lines;
+};
+
+Image *cols[NCOL];
+char buf[32000];
+Rune lorem[32000];
+
+enum
+{
+ MOUSE,
+ KEYBD,
+ RESIZE,
+ NCHAN,
+};
+
+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
+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->line, t->line+t->Frame.nlines, t->lines);
+ flushimage(display, 1);
+}
+
+void
+line2org(Text *t, uint line)
+{
+ t->line = line;
+ t->org = 0;
+ while(line > 0)
+ if(t->text[t->org++] == L'\n') line--;
+}
+
+void
+textmouse(Text *t, Mousectl *mc)
+{
+ if(scrollactive(t, mc)){
+ while(mc->buttons == 2){
+ line2org(t, scrollscr(t, mc));
+ textdraw(t);
+ readmouse(mc);
+ }
+ if(mc->buttons == 1 || mc->buttons == 8 || mc->buttons == 4 || mc->buttons == 16){
+ line2org(t, scrollscr(t, mc));
+ textdraw(t);
+ }
+ }
+}
+
+void
+textaddrunes(Text *t, Rune *s)
+{
+ Rune *rp;
+ 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);
+ for(rp = t->text+t->len; *rp != L'\0'; rp++)
+ if(*rp == L'\n') t->lines++;
+ t->len += len;
+}
+
+void
+textresize(Text *t)
+{
+ static char s[512];
+
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("%s: %r", argv0);
+ textinit(t);
+ textdraw(t);
+}
+
+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);
+}
--- a/scrolldemo/mkfile
+++ b/scrolldemo/mkfile
@@ -1,9 +1,7 @@
</$objtype/mkfile
-TARG=scrolldemo
-BIN=/$objtype/bin
+TARG=scrolldemo demolines
LIB=../libscroll.$O.a
-OFILES=scrolldemo.$O
HFILES=../scroll.h
-</sys/src/cmd/mkone
+</sys/src/cmd/mkmany