shithub: spread

Download patch

ref: eaadfa055fc6b9e7074449a8ad6b0a4ff25cb346
parent: 77302bd6af7dd1ee9f675455c8c1ba8f95fb1a07
author: sirjofri <[email protected]>
date: Tue Jul 16 07:09:48 EDT 2024

adds cell width calculation

--- a/engine.c
+++ b/engine.c
@@ -1,6 +1,7 @@
 #include <u.h>
 #include <libc.h>
 #include <bio.h>
+#include <draw.h>
 #include "spread.h"
 
 char Einitengine[] = "initengine: %r";
@@ -8,6 +9,9 @@
 int p[3];
 char *preamble;
 
+Width *firstwidth = nil;
+Width *lastwidth = nil;
+
 typedef struct Strchan Strchan;
 struct Strchan {
 	/* data */
@@ -269,6 +273,69 @@
 	}
 }
 
+static void
+calcwidth(Cell *c)
+{
+	Width *w;
+	int tw;
+	char *s;
+	
+	if (!font)
+		return;
+	
+	if (!(c->buffered || c->value))
+		return;
+	
+	s = c->buffered ? c->buffered : c->value;
+	
+	if (!firstwidth) {
+		firstwidth = mallocz(sizeof(Width), 1);
+		lastwidth = firstwidth;
+		firstwidth->column = c->p.x;
+		firstwidth->width = stringwidth(font, s);
+		return;
+	}
+	for (w = firstwidth; w; w = w->next) {
+		if (w->column != c->p.x)
+			continue;
+		w->column = c->p.x;
+		tw = stringwidth(font, s);
+		if (tw > w->width)
+			w->width = tw;
+		return;
+	}
+	lastwidth->next = mallocz(sizeof(Width), 1);
+	lastwidth = lastwidth->next;
+	lastwidth->column = c->p.x;
+	tw = stringwidth(font, s);
+	if (tw > lastwidth->width)
+		lastwidth->width = tw;
+}
+
+static void
+resetwidths(void)
+{
+	Width *w, *ow;
+	
+	for (w = firstwidth; w;) {
+		ow = w->next;
+		free(w);
+		w = ow;
+	}
+	firstwidth = lastwidth = nil;
+}
+
+int
+getwidth(int c)
+{
+	Width *w;
+	
+	for (w = firstwidth; w; w = w->next)
+		if (w->column == c)
+			return w->width;
+	return -1;
+}
+
 char Hfunc[] = "func %s() { return %s }\n";
 char Hstring[] = "func %s() { print \"%s\" }\n";
 
@@ -277,6 +344,7 @@
 {
 	char *h;
 	char *buf;
+	Response r;
 	
 	switch (c->type) {
 	case FUNCTION:
@@ -283,8 +351,8 @@
 		h = Hfunc;
 		break;
 	case STRING:
+		calcwidth(c);
 		return;
-		break;
 	default:
 		sysfatal("code error");
 	}
@@ -292,6 +360,18 @@
 	buf = smprint(h, ptoa(c->p), c->procvalue);
 	hocwrite(buf, nil);
 	free(buf);
+	
+	r = getvalue(c->p);
+	if (r.msg) {
+		c->buffered = strdup(r.msg);
+	} else {
+		if (c->buffered)
+			free(c->buffered);
+		c->buffered = nil;
+	}
+	if (!r.error)
+		calcwidth(c);
+	freeresponse(&r);
 }
 
 static void
@@ -375,16 +455,27 @@
 	
 	sortcells();
 	
+	resetwidths();
 	foreachcell(sendctohoc, nil);
 	
 	return 1;
 }
 
+static void
+unbuffer(Cell *c, void*)
+{
+	if (c->buffered)
+		free(c->buffered);
+	c->buffered = nil;
+}
+
 int
 updatecells()
 {
 	if (!sortcells())
 		return 0;
+	resetwidths();
+	foreachcell(unbuffer, nil);
 	foreachcell(sendctohoc, nil);
 	return 1;
 }
@@ -447,6 +538,12 @@
 	c = getcell(cell);
 	if (c && c->type == STRING) {
 		o.msg = strdup(c->value);
+		o.error = 0;
+		return o;
+	}
+	
+	if (c && c->buffered) {
+		o.msg = strdup(c->buffered);
 		o.error = 0;
 		return o;
 	}
--- a/spread.c
+++ b/spread.c
@@ -43,6 +43,7 @@
 	int leftpad;
 	int toppad;
 	int mathmode;
+	int minwidth;
 };
 
 void
@@ -54,15 +55,29 @@
 	d->leftpad = 2;
 	d->toppad = 2;
 	d->mathmode = 0;
+	d->minwidth = 20;
 }
 
 P
-getcelldim(Drawstate *d)
+getcelldim(P first, Drawstate *d)
 {
 	P p;
+	int nx, tx;
 	int x = Dx(d->r);
 	int y = Dy(d->r);
-	p.x = x / d->dcolwidth + 1;
+	int f;
+	
+	nx = 0;
+	f = first.x;
+	do {
+		tx = getwidth(f);
+		if (tx < d->minwidth)
+			tx = d->minwidth;
+		nx += tx;
+		f++;
+	} while (nx <= x);
+	
+	p.x = f - first.x + 1;
 	p.y = y / font->height + 1;
 	return p;
 }
@@ -70,16 +85,34 @@
 Point
 getcellpos(P cell, Drawstate *d)
 {
-	P p;
-	p.x = cell.x - d->firstcell.x;
-	p.y = cell.y - d->firstcell.y;
-	return Pt(p.x * d->dcolwidth, p.y * font->height);
+	Point pt;
+	int tw, x, y;
+	int c;
+	
+	c = d->firstcell.x;
+	x = 0;
+	while (c < cell.x) {
+		tw = getwidth(c);
+		if (tw < d->minwidth)
+			tw = d->minwidth;
+		x += tw + d->leftpad*2;
+		c++;
+	}
+	
+	y = cell.y - d->firstcell.y;
+	
+	pt.y = y * font->height;
+	pt.x = x;
+	return pt;
 }
 
 Point
 getheadpos(int x, Drawstate *d)
 {
-	return Pt(x * d->dcolwidth, - font->height);
+	P p;
+	p.x = x;
+	p.y = 0;
+	return Pt(getcellpos(p, d).x, - font->height);
 }
 
 Drawstate dstate;
@@ -151,7 +184,7 @@
 	dy = Dy(dstate.r);
 	
 	first = dstate.firstcell;
-	dim = getcelldim(&dstate);
+	dim = getcelldim(first, &dstate);
 	
 	for (x = first.x; x < first.x + dim.x; x++) {
 		cell.x = x;
@@ -405,6 +438,7 @@
 P clicktop(Point xy)
 {
 	P p;
+	int x, tx;
 	p.x = 0;
 	p.y = 0;
 	
@@ -414,10 +448,18 @@
 	
 	xy = subpt(xy, dstate.r.min);
 	
-	p.x = xy.x / dstate.dcolwidth;
-	p.y = xy.y / font->height;
+	p.x = dstate.firstcell.x;
+	x = 0;
+	do {
+		tx = getwidth(p.x);
+		if (tx < dstate.minwidth)
+			tx = dstate.minwidth;
+		x += tx + dstate.leftpad*2;
+		p.x++;
+	} while (x < xy.x);
+	p.x -= 1;
 	
-	p.x += dstate.firstcell.x;
+	p.y = xy.y / font->height;
 	p.y += dstate.firstcell.y;
 	return p;
 }
@@ -474,6 +516,7 @@
 	
 	initcolors(&colors);
 	initdrawstate(&dstate);
+	updatecells();
 	
 	eresized(0);
 	
--- a/spread.h
+++ b/spread.h
@@ -3,6 +3,7 @@
 typedef struct P P;
 typedef struct Node Node;
 typedef struct Cell Cell;
+typedef struct Width Width;
 typedef struct Response Response;
 
 #define INVALID 0
@@ -15,6 +16,7 @@
 int writefile(char *file);
 Response getvalue(P);
 void freeresponse(Response*);
+int getwidth(int);
 
 void addcell(P cell, char *value, int type);
 void rmcell(P cell);
@@ -38,16 +40,31 @@
 	int y;
 };
 
+enum {
+	Aleft,
+	Aright,
+	Acenter,
+	Adot,
+};
+
 struct Cell {
 	P p;
 	char *value;
 	int type;
 	char *procvalue;
+	char *buffered;
+	int align;
 	
 	Cell **points;
 	int size;
 	int num;
 	int indeg;
+};
+
+struct Width {
+	int column;
+	int width;
+	Width *next;
 };
 
 struct Response {