shithub: orca

Download patch

ref: 91d13854e587eae5f4928a042055cb471fc091a5
parent: 083ddca1a35977eaa9bb8c227a0d5c41cf237342
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Feb 12 18:35:33 EST 2020

plan9: selection

--- a/plan9.c
+++ b/plan9.c
@@ -12,20 +12,27 @@
 
 enum {
 	Txtoff = 16,
-
 	Msgredraw = 0,
 };
 
+typedef struct Key Key;
+
 static struct {
 	u8int u[4];
 	Usz at;
 }noteoff[16*128]; /* 16 channels, 128 notes each */
 
+struct Key {
+	int down;
+	Rune rune;
+};
+
 static Rune *linebuf;
 static Usz tick;
 static int gridw = 8, gridh = 8;
 static int bpm = 120, insert = 1, pause;
 static int curx, cury;
+static int selw = 1, selh = 1;
 static Image *curbg;
 static int charw, charh;
 static Field field;
@@ -32,6 +39,7 @@
 static Mbuf_reusable mbuf;
 static Oevent_list events;
 static char filename[256];
+static Channel *cchan;
 
 static char *menu3i[] = {
 	"load",
@@ -186,8 +194,8 @@
 static void
 redraw(void)
 {
+	Rectangle r;
 	Point p, top;
-	Rune cursor;
 	int x, y, len;
 
 	draw(screen, screen->r, display->black, nil, ZP);
@@ -195,6 +203,7 @@
 	p.x += Txtoff;
 	p.y += Txtoff;
 	top = p;
+
 	for (y = 0; y < field.height; y++) {
 		for (x = 0; x < field.width; x++) {
 			Rune c = field.buffer[field.width*y + x];
@@ -201,8 +210,6 @@
 			if (c == L'.')
 				c = L'·';
 			linebuf[x] = c;
-			if (y == cury && x == curx)
-				cursor = c;
 		}
 		linebuf[x] = 0;
 		runestring(screen, p, display->white, ZP, font, linebuf);
@@ -249,9 +256,13 @@
 
 	/* cursor bg */
 	p = top;
-	p.x += curx*stringwidth(font, " ");
-	p.y += cury*font->height;
-	runestringnbgop(screen, p, display->black, ZP, font, &cursor, 1, curbg, ZP, SoverD);
+	p.x += curx * charw;
+	p.y += cury * charh;
+	r.min = p;
+	r.max = p;
+	r.max.x += selw * charw;
+	r.max.y += selh * charh;
+	draw(screen, r, curbg, nil, ZP);
 
 	flushimage(display, 1);
 }
@@ -286,9 +297,16 @@
 static void
 fieldset(Rune key)
 {
-	field.buffer[curx + field.width*cury] = key;
-	if (!insert && curx < field.width-1)
-		curx++;
+	int y;
+
+	if (insert) {
+		for (y = cury; y < cury+selh; y++)
+			memset(&field.buffer[curx + field.width*y], key, selw);
+	} else {
+		if (curx < field.width-1)
+			curx++;
+		field.buffer[curx + field.width*cury] = key;
+	}
 }
 
 static void
@@ -303,26 +321,98 @@
 {
 }
 
+static void
+kbdproc(void *k)
+{
+	char buf[128], buf2[128], *s;
+	Channel *kchan;
+	int kfd, n;
+	Key key;
+	Rune r;
+
+	threadsetname("orca/kbd");
+	if ((kfd = open("/dev/kbd", OREAD)) < 0)
+		sysfatal("can't open kbd: %r");
+
+	kchan = k;
+	buf2[0] = 0;
+	buf2[1] = 0;
+	buf[0] = 0;
+	for(;;){
+		if (buf[0] != 0) {
+			n = strlen(buf)+1;
+			memmove(buf, buf+n, sizeof(buf)-n);
+		}
+		if (buf[0] == 0) {
+			n = read(kfd, buf, sizeof(buf)-1);
+			if (n <= 0)
+				break;
+			buf[n-1] = 0;
+			buf[n] = 0;
+		}
+
+		switch (buf[0]) {
+		case 'c':
+			if (chartorune(&r, buf+1) > 0 && r != Runeerror)
+				send(cchan, &r);
+			/* no break */
+		default:
+			continue;
+
+		case 'k':
+			s = buf+1;
+			while (*s){
+				s += chartorune(&r, s);
+				if (utfrune(buf2+1, r) == nil) {
+					key.down = 1;
+					key.rune = r;
+					send(kchan, &key);
+				}
+			}
+			break;
+
+		case 'K':
+			s = buf2+1;
+			while (*s) {
+				s += chartorune(&r, s);
+				if(utfrune(buf+1, r) == nil) {
+					key.down = 0;
+					key.rune = r;
+					send(kchan, &key);
+				}
+			}
+			break;
+		}
+		strcpy(buf2, buf);
+	}
+}
+
 void
 threadmain(int argc, char **argv)
 {
 	Mousectl *mctl;
-	Keyboardctl *kctl;
 	Field copyfield;
-	Rune key;
+	Key key;
+	Keyboardctl kctl;
 	Mouse m;
 	char tmp[256];
-	int oldw, oldh, w, h, n;
+	Channel *kchan;
+	int oldw, oldh, w, h, n, shiftdown, altdown;
 	Alt a[] = {
 		{ nil, &m, CHANRCV },
 		{ nil, nil, CHANRCV },
 		{ nil, &key, CHANRCV },
 		{ nil, nil, CHANRCV },
+		{ nil, &key.rune, CHANRCV },
 		{ nil, nil, CHANEND },
 	};
 
 	USED(argc, argv);
 
+	kchan = chancreate(sizeof(Key), 20);
+	cchan = chancreate(sizeof(Rune), 20);
+	proccreate(kbdproc, kchan, mainstacksize);
+
 	srand(time(0));
 	threadsetname("orca/draw");
 
@@ -330,15 +420,17 @@
 		sysfatal("initdraw: %r");
 	if ((mctl = initmouse(nil, screen)) == nil)
 		sysfatal("initmouse: %r");
-	if ((kctl = initkeyboard(nil)) == nil)
-		sysfatal("initkeyboard: %r");
+	kctl.c = cchan;
+	kctl.file = "/dev/null";
+	kctl.consfd = kctl.pid = kctl.ctlfd = -1;
 
 	a[0].c = mctl->c;
 	a[1].c = mctl->resizec;
-	a[2].c = kctl->c;
+	a[2].c = kchan;
 	a[3].c = chancreate(sizeof(ulong), 0); /* FIXME should it be buffered instead? */
+	a[4].c = cchan;
 
-	curbg = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, DYellow);
+	curbg = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, setalpha(DYellow, 128));
 	charw = stringwidth(font, "X");
 	charh = font->height;
 
@@ -353,6 +445,8 @@
 	oevent_list_init(&events);
 
 	threadcreate(orcathread, a[3].c, mainstacksize);
+	shiftdown = 0;
+	altdown = 0;
 
 	for (;;) {
 		redraw();
@@ -371,7 +465,7 @@
 				n = menuhit(3, mctl, &menu3, nil);
 				if (n == 0 || n == 1) {
 					strncpy(tmp, filename, sizeof(tmp));
-					if (enter("file path:", tmp, sizeof(tmp), mctl, kctl, nil) > 0) {
+					if (enter("file path:", tmp, sizeof(tmp), mctl, &kctl, nil) > 0) {
 						if (n == 0 && fieldload(tmp) == 0) {
 							w = field.width;
 							h = field.height;
@@ -389,23 +483,49 @@
 			getwindow(display, Refnone);
 			break;
 
-		case 2: /* keyboard */
-			switch (key) {
+		case 2: /* key up/down */
+			switch (key.rune) {
+			case Kshift:
+				shiftdown = key.down;
+				break;
+			case Kalt:
+				altdown = key.down;
+				break;
+			}
+			break;
+
+		case 3: /* redraw */
+			break;
+
+		case 4: /* key */
+			switch (key.rune) {
 			case 0x0b: /* C-k */
 			case Kup:
-				cury = MAX(0, cury-1);
+				if (shiftdown)
+					selh = MAX(1, selh-1);
+				else if (!altdown)
+					cury = MAX(0, cury-1);
 				break;
 			case '\n': /* C-j */
 			case Kdown:
-				cury = MIN(h-1, cury+1);
+				if (shiftdown)
+					selh++;
+				else if (!altdown)
+					cury = MIN(h-1, cury+1);
 				break;
 			case Kbs: /* C-h */
 			case Kleft:
-				curx = MAX(0, curx-1);
+				if (shiftdown)
+					selw = MAX(1, selw-1);
+				else if (!altdown)
+					curx = MAX(0, curx-1);
 				break;
 			case 0x0c: /* C-l */
 			case Kright:
-				curx = MIN(w-1, curx+1);
+				if (shiftdown)
+					selw++;
+				else if (!altdown)
+					curx = MIN(w-1, curx+1);
 				break;
 			case Khome:
 				curx = 0;
@@ -448,6 +568,8 @@
 			case Kesc:
 				if (!insert)
 					insert = 1;
+				else
+					selw = selh = 1;
 				/* FIXME else remove selection */
 				break;
 			case ' ':
@@ -456,12 +578,12 @@
 					break;
 				}
 			default:
-				if (key == Kdel || key == ' ')
-					key = '.';
-				if (orca_is_valid_glyph(key))
-					fieldset(key);
+				if (key.rune == Kdel || key.rune == ' ')
+					key.rune = '.';
+				if (orca_is_valid_glyph(key.rune))
+					fieldset(key.rune);
 				else
-					fprint(2, "unhandled key %04x\n", key);
+					fprint(2, "unhandled key %04x\n", key.rune);
 				break;
 			}
 
@@ -478,9 +600,6 @@
 					MIN(field.height, copyfield.height), MIN(field.width, copyfield.width)
 				);
 			}
-
-		case 3: /* redraw */
-			break;
 		}
 
 		if (w != oldw || h != oldh) {