ref: be943b6d7827481d7e8e7458d36983f53082315f
parent: 79f1c00150f1647e054b9d88570e63e48426ce90
author: spew <spew@palas>
date: Wed Jan 29 01:40:21 EST 2025
Add the guitest
--- /dev/null
+++ b/guitest.c
@@ -1,0 +1,180 @@
+#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 "mez.h"
+
+Mousectl *mc;
+Keyboardctl *kc;
+Image *cols[NCOL], *cmdcols[NCOL];
+char buf[8192];
+Rune lorem[8192];
+
+enum
+{
+ MOUSE,
+ KEYBD,
+ RESIZE,
+ NCHAN,
+
+ Scrollwid = 12, /* width of scroll bar */
+ Scrollgap = 4, /* gap right of scroll bar */
+ Margin = 4, /* margin around text */
+};
+
+void
+error(char *s)
+{
+ fprint(2, "%s: error: %s: %r\n", argv0, s);
+ threadexits(s);
+}
+
+void*
+emallocz(ulong sz, int clr)
+{
+ void *p;
+
+ if((p = mallocz(sz, clr)) == nil)
+ error("Out of memory");
+ setmalloctag(p, getcallerpc(&sz));
+ return p;
+}
+
+uint
+lines(Rune *text)
+{
+ Rune *e;
+ uint l;
+
+ e = text;
+ for(l = 0; e != nil; l++)
+ e = runestrchr(e+1, L'\n');
+ return l;
+}
+
+#define max(a, b) ((a)>(b)?(a):(b))
+
+Rune*
+offset(Rune *origin, int line)
+{
+ int i;
+ Rune *r;
+
+ r = origin;
+ for(i = 0; i < line; i++){
+ origin = runestrchr(r, L'\n');
+ if(origin == nil)
+ break;
+ r = origin+1;
+ }
+ return r;
+}
+
+Rectangle scrollr;
+
+void
+drawtext(Chan *chan, int resize)
+{
+ Rectangle scrollcur, bodyr;
+ int scrlines;
+
+ scrollr = screen->r;
+ scrollr.max.x = screen->r.min.x + Scrollwid + 1;
+
+ bodyr.min.x = screen->r.min.x + Scrollwid + Scrollgap + Margin;
+ bodyr.min.y = screen->r.min.y;
+ bodyr.max = screen->r.max;
+
+ scrollcur = scrollr;
+ scrlines = Dy(screen->r)/display->defaultfont->height; // How many lines on the screen.
+ scrollcur.min.y = screen->r.min.y + max(0, Dy(screen->r)*chan->curline/chan->nlines);
+ scrollcur.max.y = scrollcur.min.y+Dy(screen->r)*scrlines/chan->nlines;
+ scrollcur = insetrect(scrollcur, 1);
+
+ if(resize){
+ frclear(chan, 0);
+ frinit(chan, bodyr, display->defaultfont, screen, cols);
+ }
+
+ draw(screen, screen->r, cols[BACK], nil, ZP);
+ frinsert(chan, offset(chan->body, chan->curline), chan->body + chan->bodylen, 0);
+ draw(screen, scrollr, cols[BORD], nil, ZP);
+ draw(screen, scrollcur, cols[BACK], nil, ZP);
+ flushimage(display, 1);
+}
+
+void
+setcurline(int y, Chan *chan)
+{
+ chan->curline = (y-scrollr.min.y)*chan->nlines/Dy(scrollr);
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ Rune r, *rs;
+ Mouse m;
+ Chan *chan;
+ char *s;
+ int len;
+
+ len = readn(0, buf, sizeof(buf));
+ buf[len] = '\0';
+ for(s = buf, rs = lorem; *s != '\0'; s+=len, rs++)
+ len = chartorune(rs, s);
+
+ if(initdraw(nil, nil, "guitest") < 0)
+ sysfatal("initdraw: %r");
+ if((mc = initmouse(nil, screen)) == nil)
+ sysfatal("initmouse failed: %r");
+ if((kc = initkeyboard(nil)) == nil)
+ sysfatal("initmouse failed: %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;
+ chan = emallocz(sizeof(*chan), 1);
+ chan->body = lorem;
+ chan->bodylen = runestrlen(chan->body);
+ chan->nlines = lines(chan->body);
+
+ Alt a[NCHAN+1] = {
+ [MOUSE] = {mc->c, &m, CHANRCV},
+ [RESIZE] = {mc->resizec, nil, CHANRCV},
+ [KEYBD] = {kc->c, &r, CHANRCV},
+ [NCHAN] = {nil, nil, CHANEND},
+ };
+ drawtext(chan, 1);
+ for(;;){
+ switch(alt(a)){
+ default:
+ break;
+ case KEYBD:
+ if(r == Kdel)
+ goto end;
+ break;
+ case MOUSE:
+ if(!ptinrect(m.xy, scrollr))
+ break;
+ while(m.buttons == 2){
+ setcurline(m.xy.y, chan);
+ drawtext(chan, 0);
+ readmouse(mc);
+ m = *mc;
+ }
+ break;
+ case RESIZE:
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("%s: %r", argv0);
+ drawtext(chan, 1);
+ break;
+ }
+ }
+end:
+ threadexitsall(0);
+}