ref: eaadfa055fc6b9e7074449a8ad6b0a4ff25cb346
parent: 77302bd6af7dd1ee9f675455c8c1ba8f95fb1a07
author: sirjofri <sirjofri@sirjofri.de>
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 {