shithub: mez

Download patch

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