feat: Variable row heights and overall font size

This update adds a command-line option, which only affects fteapot,
  to set the overall font size in pixels.
  It also allows the row heights to be set, in units of 1/ROWHEIGHT_DENOMINATOR
  rows (although only the integer part of the row height is relevant in
  the terminal spreadsheet).
  Still needs a menu option for row heights in fteapot and documentation.
This commit is contained in:
Glen Whitney 2023-04-08 15:39:40 -04:00
parent 118374c46e
commit c9966d47c7
7 changed files with 281 additions and 88 deletions

View File

@ -3,8 +3,17 @@
#include <stdlib.h> #include <stdlib.h>
/* default width of a column */ /* default width of a column (in "characters") */
#define DEF_COLUMNWIDTH 12 #define DEF_COLUMNWIDTH 12
/* The number of vertical slices to divide a row into.
Note that only integer multiples of this have any effect
in console mode, but fteapot can save and respect non-
integer multiples of this value */
#define ROWHEIGHT_DENOMINATOR 12
/* default height of a row, in units of ROWHEIGHT_DENOMINATOR,
i.e. these should be equal to make the default height be one.
*/
#define DEF_ROWHEIGHT 12
/* default precision of a printed value */ /* default precision of a printed value */
/* Since the default format now counts significant figures /* Since the default format now counts significant figures

View File

@ -39,6 +39,7 @@ unsigned int batchln=0;
PrecisionLevel def_precision = DEF_PRECISION; PrecisionLevel def_precision = DEF_PRECISION;
StringFormat quote = DIRECT_STRING; StringFormat quote = DIRECT_STRING;
bool header = true; bool header = true;
int fontsize = 14;
bool always_redraw = false; bool always_redraw = false;
int debug_level = 0; int debug_level = 0;
static bool usexdr = false; static bool usexdr = false;
@ -67,13 +68,13 @@ void moveto(Sheet *sheet, CoordT x, CoordT y, CoordT z)
need_redraw = true; need_redraw = true;
sheet->offy = (sheet->cur[Y] > 0) ? sheet->cur[Y]-1 : 0; sheet->offy = (sheet->cur[Y] > 0) ? sheet->cur[Y]-1 : 0;
} }
if (sheet->cur[X] >= sheet->offx + sheet->maxx) { if (sheet->cur[X] >= sheet->offx + (CoordT)sheet->maxx) {
need_redraw = true; need_redraw = true;
sheet->offx = sheet->cur[X] - sheet->maxx + 2; sheet->offx = sheet->cur[X] - (CoordT)sheet->maxx + 2;
} }
if (sheet->cur[Y] >= sheet->offy + sheet->maxy) { if (sheet->cur[Y] >= sheet->offy + (CoordT)sheet->maxy) {
need_redraw = true; need_redraw = true;
sheet->offy = sheet->cur[Y] - sheet->maxy + 2; sheet->offy = sheet->cur[Y] - (CoordT)sheet->maxy + 2;
} }
if (need_redraw) redraw_sheet(sheet); if (need_redraw) redraw_sheet(sheet);
else if (need_cell) redraw_cell(sheet, sheet->cur); else if (need_cell) redraw_cell(sheet, sheet->cur);
@ -312,6 +313,23 @@ static int do_columnwidth(Sheet *cursheet)
} }
/*}}}*/ /*}}}*/
/* do_rowheight -- set the row height */ /*{{{*/
static int do_rowheight(Sheet *cursheet)
{
do_mark(cursheet, GET_MARK_CUR);
int n = (int)rowheight(cursheet, cursheet->mark1[Y], cursheet->mark1[Z]);
do {
int c = line_numedit(&n, _("Row height:"));
if (c < 0) return c;
} while (n <= 0);
RowHgtT rh = (RowHgtT)n;
for (int y = cursheet->mark1[Y]; y <= cursheet->mark2[Y]; ++y)
for (int z = cursheet->mark1[Z]; z <= cursheet->mark2[Z]; ++z)
setheight(cursheet, y, z, rh);
return -1;
}
/*}}}*/
/* do_attribute -- set cell attributes */ /*{{{*/ /* do_attribute -- set cell attributes */ /*{{{*/
static void do_attribute(Sheet *cursheet, Key action) static void do_attribute(Sheet *cursheet, Key action)
{ {
@ -1329,6 +1347,7 @@ int do_sheetcmd(Sheet *cursheet, Key c, bool moveonly)
{ {
case K_GOTO: do_goto(cursheet, (const char *)0); break; case K_GOTO: do_goto(cursheet, (const char *)0); break;
case K_COLWIDTH: do_columnwidth(cursheet); break; case K_COLWIDTH: do_columnwidth(cursheet); break;
case K_ROWHEIGHT: do_rowheight(cursheet); break;
case BLOCK_CLEAR: do_clear(cursheet); update(cursheet); break; case BLOCK_CLEAR: do_clear(cursheet); update(cursheet); break;
case BLOCK_INSERT: do_insert(cursheet); update(cursheet); break; case BLOCK_INSERT: do_insert(cursheet); update(cursheet); break;
case BLOCK_DELETE: do_delete(cursheet); update(cursheet); break; case BLOCK_DELETE: do_delete(cursheet); update(cursheet); break;
@ -1577,19 +1596,20 @@ int do_sheetcmd(Sheet *cursheet, Key c, bool moveonly)
/* NPAGE -- page down */ /*{{{*/ /* NPAGE -- page down */ /*{{{*/
case K_NPAGE: case K_NPAGE:
{ {
cursheet->offy += (cursheet->maxy-3); cursheet->offy += ((CoordT)(cursheet->maxy)-3);
relmoveto(cursheet, 0, cursheet->maxy-3, 0); relmoveto(cursheet, 0, (CoordT)(cursheet->maxy)-3, 0);
break; break;
} }
/*}}}*/ /*}}}*/
/* PPAGE -- page up */ /*{{{*/ /* PPAGE -- page up */ /*{{{*/
case K_PPAGE: case K_PPAGE:
{ {
cursheet->offy = cursheet->offy >= cursheet->maxy - 3 cursheet->offy =
? cursheet->offy - cursheet->maxy + 3 : 0; cursheet->offy >= (CoordT)(cursheet->maxy) - 3
? cursheet->offy - (CoordT)(cursheet->maxy) + 3 : 0;
relmoveto(cursheet, 0, relmoveto(cursheet, 0,
cursheet->cur[Y] >= (cursheet->maxy - 3) cursheet->cur[Y] >= ((CoordT)(cursheet->maxy) - 3)
? -(cursheet->maxy - 3) : -cursheet->cur[Y], ? -((CoordT)(cursheet->maxy) - 3) : -cursheet->cur[Y],
0); 0);
break; break;
} }
@ -1645,7 +1665,7 @@ int main(int argc, char *argv[])
find_helpfile(helpfile, sizeof(helpfile), argv[0]); find_helpfile(helpfile, sizeof(helpfile), argv[0]);
/* parse options */ /*{{{*/ /* parse options */ /*{{{*/
while ((o=getopt(argc,argv,"bdhnrqHp:?"))!=EOF) switch (o) while ((o=getopt(argc,argv,"bdhnrqHp:F:?"))!=EOF) switch (o)
{ {
/* b -- run batch */ /*{{{*/ /* b -- run batch */ /*{{{*/
case 'b': batch = true; break; case 'b': batch = true; break;
@ -1687,19 +1707,35 @@ int main(int argc, char *argv[])
break; break;
} }
/*}}}*/ /*}}}*/
/* F -- font size */ /*{{{*/
case 'F':
{
long f;
char *end;
f = strtol(optarg, &end, 0);
if (*end || f < 1) {
fprintf(stderr, _("teapot: font size must be positive.\n"));
exit(1);
}
fontsize = (int)f;
break;
}
/*}}}*/
/* default -- includes ? and h */ /*{{{*/ /* default -- includes ? and h */ /*{{{*/
default: default:
{ {
fprintf(stderr,_( fprintf(stderr,_(
"Usage: %s [-a] [-b] [-d]* [-h] [-n|-q] [-H] [-r] [-p digits] [file]\n" "Usage: %s [-abFhHr] [-d]* [-n|-q] [-p digits] [file]\n"
" -a: use ASCII file format as default\n" " -a: use ASCII file format as default\n"
" -b: batch mode\n" " -b: batch mode\n"
" -d: increase debug level, once for each occurrence\n" " -d: increase debug level, once for each occurrence\n"
" -F nn: set font size to nn\n"
" -h: print this message and exit\n" " -h: print this message and exit\n"
" -n|-q: DO NOT or DO display strings in quotes, respectively\n"
" -H: hide row/column headers\n" " -H: hide row/column headers\n"
" -n|-q: DO NOT or DO display strings in quotes, respectively\n"
" -p nn: set decimal precision to nn\n"
" -r: redraw more often\n" " -r: redraw more often\n"
" -p: set decimal precision\n"
), argv[0]); ), argv[0]);
exit(1); exit(1);
} }

View File

@ -17,6 +17,7 @@ extern bool batch;
extern PrecisionLevel def_precision; extern PrecisionLevel def_precision;
extern StringFormat quote; extern StringFormat quote;
extern bool header; extern bool header;
extern int fontsize;
extern int debug_level; extern int debug_level;
extern bool always_redraw; extern bool always_redraw;
extern unsigned int batchln; extern unsigned int batchln;
@ -94,7 +95,8 @@ typedef enum
ADJUST_BACKGROUND = -63, ADJUST_BACKGROUND = -63,
K_EDIT_STYLE_EXPR = -64, K_EDIT_STYLE_EXPR = -64,
ADJUST_DIM = -65, ADJUST_DIM = -65,
ADJUST_ITALIC = -66 ADJUST_ITALIC = -66,
K_ROWHEIGHT = -67
} Key; } Key;
extern int do_sheetcmd(Sheet *cursheet, Key c, bool moveonly); extern int do_sheetcmd(Sheet *cursheet, Key c, bool moveonly);

View File

@ -226,6 +226,7 @@ void initialize_sheet(Sheet *sheet) {
sheet->dim[X] = sheet->dim[Y] = sheet->dim[Z] = 0; sheet->dim[X] = sheet->dim[Y] = sheet->dim[Z] = 0;
sheet->sheet = (Cell**)0; sheet->sheet = (Cell**)0;
sheet->column = (ColWidT*)0; sheet->column = (ColWidT*)0;
sheet->rowhts = (RowHgtT*)0;
sheet->orix = sheet->oriy = 0; sheet->orix = sheet->oriy = 0;
sheet->maxx = sheet->maxy = 0; sheet->maxx = sheet->maxy = 0;
sheet->name = (char*)0; sheet->name = (char*)0;
@ -272,7 +273,7 @@ void resize(Sheet *sheet, CoordT x, CoordT y, CoordT z, bool *qextended)
if (sheet->sheet!=(Cell**)0) free(sheet->sheet); if (sheet->sheet!=(Cell**)0) free(sheet->sheet);
sheet->sheet = dummy.sheet; sheet->sheet = dummy.sheet;
/*}}}*/ /*}}}*/
/* allocate new columns */ /*{{{*/ /* allocate new column widths and row heights */ /*{{{*/
if ((size_t)x > sheet->dim[X] || (size_t)z >= sheet->dim[Z]) if ((size_t)x > sheet->dim[X] || (size_t)z >= sheet->dim[Z])
{ {
dummy.column = malloc(dummy.dim[X] * dummy.dim[Z] * sizeof(ColWidT)); dummy.column = malloc(dummy.dim[X] * dummy.dim[Z] * sizeof(ColWidT));
@ -281,7 +282,7 @@ void resize(Sheet *sheet, CoordT x, CoordT y, CoordT z, bool *qextended)
{ {
if ((size_t)x < sheet->dim[X] && (size_t)z < sheet->dim[Z]) if ((size_t)x < sheet->dim[X] && (size_t)z < sheet->dim[Z])
*(dummy.column + ((size_t)x)*dummy.dim[Z] + (size_t)z) *(dummy.column + ((size_t)x)*dummy.dim[Z] + (size_t)z)
= *(sheet->column + ((size_t)x)*sheet->dim[Z] + z); = *(sheet->column + ((size_t)x)*sheet->dim[Z] + (size_t)z);
else else
*(dummy.column + ((size_t)x)*dummy.dim[Z] + (size_t)z) *(dummy.column + ((size_t)x)*dummy.dim[Z] + (size_t)z)
= DEF_COLUMNWIDTH; = DEF_COLUMNWIDTH;
@ -289,6 +290,21 @@ void resize(Sheet *sheet, CoordT x, CoordT y, CoordT z, bool *qextended)
if (sheet->column != (ColWidT*)0) free(sheet->column); if (sheet->column != (ColWidT*)0) free(sheet->column);
sheet->column = dummy.column; sheet->column = dummy.column;
} }
if ((size_t)(y) > sheet->dim[Y] || (size_t)z > sheet->dim[Z])
{
dummy.rowhts = malloc(dummy.dim[Y] * dummy.dim[Z] * sizeof(RowHgtT));
for (y=0; (size_t)y < dummy.dim[Y]; ++y)
for (z=0; (size_t)z < dummy.dim[Z]; ++z)
{
RowHgtT *dumht = dummy.rowhts + ((size_t)y)*dummy.dim[Z] + (size_t)z;
if ((size_t)y < sheet->dim[Y] && (size_t)z < sheet->dim[Z])
*dumht = *(sheet->rowhts + ((size_t)y)*sheet->dim[Z] + (size_t)z);
else
*dumht = DEF_ROWHEIGHT;
}
if (sheet->rowhts != (RowHgtT*)0) free(sheet->rowhts);
sheet->rowhts = dummy.rowhts;
}
/*}}}*/ /*}}}*/
for (Dimensions dd = X; dd < HYPER; ++dd) sheet->dim[dd] = dummy.dim[dd]; for (Dimensions dd = X; dd < HYPER; ++dd) sheet->dim[dd] = dummy.dim[dd];
} }
@ -408,12 +424,16 @@ void freesheet(Sheet *sheet, int all)
} /*}}}*/ } /*}}}*/
if (sheet->sheet) free(sheet->sheet); if (sheet->sheet) free(sheet->sheet);
if (sheet->column) free(sheet->column); if (sheet->column) free(sheet->column);
if (sheet->rowhts) free(sheet->rowhts);
if (sheet->name) free(sheet->name); if (sheet->name) free(sheet->name);
if (!batch) display_end(sheet); if (!batch) display_end(sheet);
} else { } else {
for (size_t x = 0; x < sheet->dim[X]; ++x) for (size_t x = 0; x < sheet->dim[X]; ++x)
for (size_t z = 0; z < sheet->dim[Z]; ++z) for (size_t z = 0; z < sheet->dim[Z]; ++z)
*(sheet->column + x*sheet->dim[Z] + z) = DEF_COLUMNWIDTH; *(sheet->column + x*sheet->dim[Z] + z) = DEF_COLUMNWIDTH;
for (size_t y = 0; y < sheet->dim[y]; ++y)
for (size_t z = 0; z < sheet->dim[Z]; ++z)
*(sheet->rowhts + y*sheet->dim[Z] + z) = DEF_ROWHEIGHT;
cachelabels(sheet); cachelabels(sheet);
forceupdate(sheet); forceupdate(sheet);
} }
@ -460,6 +480,17 @@ ColWidT columnwidth(Sheet *sheet, CoordT x, CoordT z)
} }
/*}}}*/ /*}}}*/
/* rowheight -- get height of row */ /*{{{*/
ColWidT rowheight(Sheet *sheet, CoordT y, CoordT z)
{
assert(sheet!=(Sheet*)0);
if ((size_t)y < sheet->dim[Y] && (size_t)z < sheet->dim[Z])
return (*(sheet->rowhts + ((size_t)y)*sheet->dim[Z] + (size_t)z));
else return DEF_ROWHEIGHT;
}
/*}}}*/
/* setwidth -- set width of column */ /*{{{*/ /* setwidth -- set width of column */ /*{{{*/
bool setwidth(Sheet *sheet, CoordT x, CoordT z, ColWidT width) bool setwidth(Sheet *sheet, CoordT x, CoordT z, ColWidT width)
{ {
@ -477,6 +508,24 @@ bool setwidth(Sheet *sheet, CoordT x, CoordT z, ColWidT width)
} }
/*}}}*/ /*}}}*/
/* setheight -- set height of row */ /*{{{*/
bool setheight(Sheet *sheet, CoordT y, CoordT z, RowHgtT height)
{
assert(sheet != (Sheet*)0);
bool isbigger = false;
resize(sheet, 1, y, z, &isbigger);
if (isbigger) sheet->changed = true;
RowHgtT *storage = sheet->rowhts + (size_t)y*sheet->dim[Z] + (size_t)z;
if (*storage != height) {
*storage = height;
sheet->changed = true;
return true;
}
return isbigger;
}
/*}}}*/
/* cellwidth -- get width of a cell */ /*{{{*/ /* cellwidth -- get width of a cell */ /*{{{*/
ColWidT cellwidth(Sheet *sheet, const Location at) ColWidT cellwidth(Sheet *sheet, const Location at)
{ {
@ -489,6 +538,18 @@ ColWidT cellwidth(Sheet *sheet, const Location at)
} }
/*}}}*/ /*}}}*/
/* cellheight -- get height of a cell */ /*{{{*/
RowHgtT cellheight(Sheet *sheet, const Location at)
{
/* At the moment this is trivial because there is no vertical
"shadowing". Probably rather than implementing that more
general cell merging would be a preferable way to go
*/
return rowheight(sheet, at[Y], at[Z]);
}
/*}}}*/
/* putcont -- assign new contents */ /*{{{*/ /* putcont -- assign new contents */ /*{{{*/
void puttok(Sheet *sheet, const Location at, Token t, TokVariety v) void puttok(Sheet *sheet, const Location at, Token t, TokVariety v)
{ {
@ -1232,6 +1293,8 @@ const char *saveport(Sheet *sheet, const char *name, unsigned int *count)
{ {
if (y == 0 && columnwidth(sheet,x,z) != DEF_COLUMNWIDTH) if (y == 0 && columnwidth(sheet,x,z) != DEF_COLUMNWIDTH)
fprintf(fp,"W%d %d %zu\n", x, z, columnwidth(sheet,x,z)); fprintf(fp,"W%d %d %zu\n", x, z, columnwidth(sheet,x,z));
if (x == 0 && rowheight(sheet, y, z) != DEF_ROWHEIGHT)
fprintf(fp, "Y%d %d %zu\n", y, z, rowheight(sheet, y, z));
Cell *cell = CELL_ATC(sheet,x,y,z); Cell *cell = CELL_ATC(sheet,x,y,z);
if (cell != NULLCELL) if (cell != NULLCELL)
{ {
@ -1283,6 +1346,7 @@ const char *loadport(Sheet *sheet, const char *name)
size_t width = strlen(buf); size_t width = strlen(buf);
if (width > 0 && buf[width-1] == '\n') buf[--width] = '\0'; if (width > 0 && buf[width-1] == '\n') buf[--width] = '\0';
/*}}}*/ /*}}}*/
bool is_height = false;
switch (buf[0]) switch (buf[0])
{ {
/* C -- parse cell */ /*{{{*/ /* C -- parse cell */ /*{{{*/
@ -1548,16 +1612,21 @@ const char *loadport(Sheet *sheet, const char *name)
break; break;
} }
/*}}}*/ /*}}}*/
/* Y -- row height */
case 'Y':
is_height = true;
/* FALL THROUGH */
/* W -- column width */ /*{{{*/ /* W -- column width */ /*{{{*/
case 'W': case 'W':
{ {
/* parse x and z */ /*{{{*/ /* parse x/y and z */ /*{{{*/
const char *os = buf+1; const char *os = buf+1;
char *ns = buf+1; char *ns = buf+1;
CoordT cx = (CoordT)strtol(os, &ns, 0); CoordT cxy = (CoordT)strtol(os, &ns, 0);
if (os == ns) if (os == ns)
{ {
sprintf(errbuf, _("Parse error for x position in line %d"), line); sprintf(errbuf, _("Parse error for %c position in line %d"),
is_height ? 'y' : 'x', line);
err = errbuf; err = errbuf;
goto eek; goto eek;
} }
@ -1571,10 +1640,10 @@ const char *loadport(Sheet *sheet, const char *name)
goto eek; goto eek;
} }
/*}}}*/ /*}}}*/
/* parse width */ /*{{{*/ /* parse width/height */ /*{{{*/
while (*ns == ' ') ++ns; while (*ns == ' ') ++ns;
os = ns; os = ns;
ColWidT cwidth = (ColWidT)strtol(os, &ns, 0); long extent = strtol(os, &ns, 0);
if (os == ns) if (os == ns)
{ {
sprintf(errbuf, _("Parse error for width in line %d"), line); sprintf(errbuf, _("Parse error for width in line %d"), line);
@ -1582,7 +1651,8 @@ const char *loadport(Sheet *sheet, const char *name)
goto eek; goto eek;
} }
/*}}}*/ /*}}}*/
setwidth(sheet, cx, cz, cwidth); if (is_height) setheight(sheet, cxy, cz, (RowHgtT)extent);
else setwidth(sheet, cxy, cz, (ColWidT)extent);
break; break;
} }
/*}}}*/ /*}}}*/

View File

@ -13,6 +13,7 @@ extern "C" {
#define ASCENDING 001 #define ASCENDING 001
typedef size_t ColWidT; typedef size_t ColWidT;
typedef size_t RowHgtT; /* Note measured in units of ROWHEIGHT_DENOMINATOR */
typedef struct typedef struct
{ {
@ -38,9 +39,10 @@ typedef struct
CoordT offx, offy; CoordT offx, offy;
Cell **sheet; Cell **sheet;
ColWidT *column; ColWidT *column;
RowHgtT *rowhts;
size_t dim[HYPER]; size_t dim[HYPER];
size_t orix, oriy; size_t orix, oriy;
CoordT maxx, maxy; size_t maxx, maxy;
size_t width; size_t width;
char *name; char *name;
void *display; void *display;
@ -86,6 +88,9 @@ void freecellofsheet(Sheet *sheet, const Location at);
ColWidT columnwidth(Sheet *sheet, CoordT x, CoordT z); ColWidT columnwidth(Sheet *sheet, CoordT x, CoordT z);
bool setwidth(Sheet *sheet, CoordT x, CoordT z, ColWidT width); bool setwidth(Sheet *sheet, CoordT x, CoordT z, ColWidT width);
ColWidT cellwidth(Sheet *sheet, const Location at); ColWidT cellwidth(Sheet *sheet, const Location at);
RowHgtT rowheight(Sheet *sheet, CoordT y, CoordT z);
bool setheight(Sheet *sheet, CoordT y, CoordT x, RowHgtT height);
RowHgtT cellheight(Sheet *sheet, const Location at);
void puttok(Sheet *sheet, const Location at, Token t, TokVariety v); void puttok(Sheet *sheet, const Location at, Token t, TokVariety v);
Token recompvalue(Sheet *sheet, const Location at); Token recompvalue(Sheet *sheet, const Location at);
Token evaluate_at(Token t, Sheet *sheet, const Location at); Token evaluate_at(Token t, Sheet *sheet, const Location at);

View File

@ -272,15 +272,16 @@ static int do_block(Sheet *cursheet)
} }
int show_menu(Sheet *cursheet) Key show_menu(Sheet *cursheet)
{ {
int c = K_INVALID; int c = K_INVALID;
do do
{ {
const char* menu[] = const char* menu[] =
{ _("aA)ttributes"), _("wW)idth"), _("bB)lock"), _("fF)ile"), { _("aA)ttributes"), _("wW)idth"), _("hH)eight"), _("bB)lock"),
_("gG)oto"), _("sS)hell"), _("vV)ersion"), _("qQ)uit"), NULL _("fF)ile"), _("gG)oto"), _("sS)hell"), _("vV)ersion"),
_("qQ)uit"), NULL
}; };
switch (c=line_menu(_("Main menu:"),menu,0)) switch (c=line_menu(_("Main menu:"),menu,0))
{ {
@ -288,12 +289,13 @@ int show_menu(Sheet *cursheet)
case -1: c = KEY_CANCEL; break; case -1: c = KEY_CANCEL; break;
case 0: c = do_attribute(cursheet); break; case 0: c = do_attribute(cursheet); break;
case 1: c = K_COLWIDTH; break; case 1: c = K_COLWIDTH; break;
case 2: c = do_block(cursheet); break; case 2: c = K_ROWHEIGHT; break;
case 3: c = do_file(cursheet); break; case 3: c = do_block(cursheet); break;
case 4: c = K_GOTO; break; case 4: c = do_file(cursheet); break;
case 5: do_shell(); c = KEY_CANCEL; break; case 5: c = K_GOTO; break;
case 6: c = K_ABOUT; break; case 6: do_shell(); c = KEY_CANCEL; break;
case 7: c = K_QUIT; break; case 7: c = K_ABOUT; break;
case 8: c = K_QUIT; break;
default: assert(0); default: assert(0);
} }
} while (c == K_INVALID); } while (c == K_INVALID);
@ -327,8 +329,8 @@ static void do_bg(void)
void display_main(Sheet *cursheet) void display_main(Sheet *cursheet)
{ {
cursheet->maxx = COLS; cursheet->maxx = (size_t)COLS;
cursheet->maxy = LINES-1; cursheet->maxy = (size_t)(LINES-1);
Key k; Key k;
do do
@ -396,10 +398,15 @@ void redraw_cell(Sheet *sheet, const Location at )
update(sheet); update(sheet);
} }
static RowHgtT eff_height(Sheet *sheet, CoordT y) {
RowHgtT eff = rowheight(sheet, y, sheet->cur[Z]) / ROWHEIGHT_DENOMINATOR;
if (eff == 0) return 1;
return eff;
}
/* redraw_sheet -- draw a sheet with cell cursor */ /* redraw_sheet -- draw a sheet with cell cursor */
void redraw_sheet(Sheet *sheet) void redraw_sheet(Sheet *sheet)
{ {
int x,y;
char pbuf[80]; char pbuf[80];
char *buf=malloc(128); char *buf=malloc(128);
size_t bufsz=128; size_t bufsz=128;
@ -421,18 +428,31 @@ void redraw_sheet(Sheet *sheet)
--(sheet->cur[X]); --(sheet->cur[X]);
assert(sheet->cur[X] >= 0); assert(sheet->cur[X] >= 0);
} }
if (sheet->cur[Y] - sheet->offy > sheet->maxy - 2 - (header ? 1 : 0)) /* Calculate the nearest Y offset that will show the current row */
sheet->offy = sheet->cur[Y] - sheet->maxy + 2 + (header ? 1 : 0);
if (sheet->cur[Y] < sheet->offy) sheet->offy = sheet->cur[Y]; if (sheet->cur[Y] < sheet->offy) sheet->offy = sheet->cur[Y];
else {
size_t available = sheet->maxy - 2 - (header ? 1 : 0);
CoordT newoffy = sheet->cur[Y];
size_t needed = eff_height(sheet, newoffy);
while (needed < available && newoffy > 0) {
RowHgtT prevhgt = eff_height(sheet, newoffy - 1);
if (needed + prevhgt > available) break;
needed += prevhgt;
--newoffy;
}
if (newoffy > sheet->offy) sheet->offy = newoffy;
}
/* Calculate the nearest X offset that will show the current column */
if (sheet->cur[X] < sheet->offx) sheet->offx = sheet->cur[X]; if (sheet->cur[X] < sheet->offx) sheet->offx = sheet->cur[X];
size_t width = header ? 4 : 0; else {
bool again; size_t width = header ? 4 : 0;
size_t col; bool again;
do size_t col;
{ do
{
again = false; again = false;
col = 0; col = 0;
for (x = sheet->offx; for (CoordT x = sheet->offx;
width <= (size_t)(sheet->maxx); width <= (size_t)(sheet->maxx);
width += columnwidth(sheet, x, sheet->cur[Z]), ++x, ++col); width += columnwidth(sheet, x, sheet->cur[Z]), ++x, ++col);
--col; --col;
@ -444,7 +464,8 @@ void redraw_sheet(Sheet *sheet)
sheet->offx++; again = true; sheet->offx++; again = true;
} }
} }
} while (again); } while (again);
}
short curcp = 1; short curcp = 1;
init_pair(curcp, DefaultCN[FOREGROUND], COLOR_YELLOW); init_pair(curcp, DefaultCN[FOREGROUND], COLOR_YELLOW);
@ -452,15 +473,15 @@ void redraw_sheet(Sheet *sheet)
if (header) { if (header) {
(void)wattron(stdscr,DEF_NUMBER); (void)wattron(stdscr,DEF_NUMBER);
/* draw x numbers */ /* draw x numbers */
for (width=4; width < (size_t)(sheet->maxx); ++width) for (size_t width=4; width < (size_t)(sheet->maxx); ++width)
mvwaddch(stdscr, (int)(sheet->oriy), (int)(sheet->orix + width), mvwaddch(stdscr, (int)(sheet->oriy), (int)(sheet->orix + width),
(chtype)(unsigned char)' '); (chtype)(unsigned char)' ');
for (width = 4, x = sheet->offx; width < (size_t)(sheet->maxx); ColWidT width = 4;
width += col, ++x) for (CoordT x = sheet->offx; width < sheet->maxx; ++x)
{ {
short usecp = 0; short usecp = 0;
if (x == sheet->cur[X]) usecp = curcp; if (x == sheet->cur[X]) usecp = curcp;
col = columnwidth(sheet, x, sheet->cur[Z]); ColWidT col = columnwidth(sheet, x, sheet->cur[Z]);
if (bufsz<(size_t)(col*UTF8SZ+1)) buf=realloc(buf,bufsz=(size_t)(col*UTF8SZ+1)); if (bufsz<(size_t)(col*UTF8SZ+1)) buf=realloc(buf,bufsz=(size_t)(col*UTF8SZ+1));
snprintf(buf,bufsz,"%d",x); snprintf(buf,bufsz,"%d",x);
if (mbslen(buf)>col) { if (mbslen(buf)>col) {
@ -473,18 +494,27 @@ void redraw_sheet(Sheet *sheet)
buf[(size_t)(sheet->maxx)-width] = '\0'; buf[(size_t)(sheet->maxx)-width] = '\0';
wcolor_set(stdscr, usecp, NULL); wcolor_set(stdscr, usecp, NULL);
mvwaddstr(stdscr, (int)(sheet->oriy), (int)(sheet->orix+width), buf); mvwaddstr(stdscr, (int)(sheet->oriy), (int)(sheet->orix+width), buf);
ColWidT used = strlen(buf);
while (used++ < col) waddch(stdscr, (chtype)(unsigned char)' ');
wcolor_set(stdscr, 0, NULL); wcolor_set(stdscr, 0, NULL);
width += col;
} }
/* draw y numbers */ /* draw y numbers */
for (y=1; y < sheet->maxy - 1; ++y) { RowHgtT height = 1;
for (CoordT y = sheet->offy; height + 1 < sheet->maxy; ++y) {
short usecp = 0; short usecp = 0;
CoordT realy = y - 1 + sheet->offy; if (y == sheet->cur[Y]) usecp = curcp;
if (realy == sheet->cur[Y]) usecp = curcp;
wcolor_set(stdscr, usecp, NULL); wcolor_set(stdscr, usecp, NULL);
(void)mvwprintw(stdscr, y + (CoordT)(sheet->oriy), (CoordT)(sheet->orix), (void)mvwprintw(stdscr, (int)(height+sheet->oriy), (int)sheet->orix,
"%-4d", y-1 + (int)(sheet->offy)); "%-4d", y);
RowHgtT rows = eff_height(sheet, y);
for (RowHgtT extra = 1; extra < rows; ++extra) {
mvwaddstr(stdscr, (int)(height+extra+sheet->oriy), (int)sheet->orix,
" ");
}
wcolor_set(stdscr, 0, NULL); wcolor_set(stdscr, 0, NULL);
height += eff_height(sheet, y);
} }
(void)wattroff(stdscr,DEF_NUMBER); (void)wattroff(stdscr,DEF_NUMBER);
@ -494,11 +524,14 @@ void redraw_sheet(Sheet *sheet)
} }
++curcp; ++curcp;
/* draw elements */ /* draw elements */
for (y = header ? 1 : 0; y < sheet->maxy - 1; ++y) RowHgtT height = header ? 1 : 0;
for (width = header ? 4 : 0, x = sheet->offx; for (CoordT y = sheet->offy; height + 1 < sheet->maxy; ++y) {
width < (size_t)sheet->maxx; RowHgtT rows = eff_height(sheet, y);
ColWidT width = header ? 4 : 0;
for (CoordT x = sheet->offx;
width < sheet->maxx;
width += columnwidth(sheet, x, sheet->cur[Z]), ++x) width += columnwidth(sheet, x, sheet->cur[Z]), ++x)
{ {
size_t size,realsize,fill, cutoff = 0; size_t size,realsize,fill, cutoff = 0;
int realx = x; int realx = x;
if (x == sheet->offx) { if (x == sheet->offx) {
@ -511,7 +544,7 @@ void redraw_sheet(Sheet *sheet)
cutoff += columnwidth(sheet, realx, sheet->cur[Z]); cutoff += columnwidth(sheet, realx, sheet->cur[Z]);
} }
} }
tmp[X] = realx; tmp[Y] = y - (header ? 1 : 0) + sheet->offy; tmp[X] = realx; tmp[Y] = y;
tmp[Z] = sheet->cur[Z]; tmp[Z] = sheet->cur[Z];
cell = safe_cell_at(sheet, tmp); cell = safe_cell_at(sheet, tmp);
Style sc = getstyle(sheet, tmp); Style sc = getstyle(sheet, tmp);
@ -548,21 +581,30 @@ void redraw_sheet(Sheet *sheet)
wcolor_set(stdscr, usecp, NULL); wcolor_set(stdscr, usecp, NULL);
bool invert = bool invert =
(ms != UNMARKED) && loc_in_box(tmp, sheet->mark1, sheet->mark2); (ms != UNMARKED) && loc_in_box(tmp, sheet->mark1, sheet->mark2);
if (x == sheet->cur[X] if (x == sheet->cur[X] && y == sheet->cur[Y])
&& (y - (header ? 1 : 0) + sheet->offy == sheet->cur[Y]))
invert = (ms == MARKING) ? true : !invert; invert = (ms == MARKING) ? true : !invert;
if (invert) (void)wattron(stdscr,DEF_CELLCURSOR); if (invert) (void)wattron(stdscr,DEF_CELLCURSOR);
if (sc.dim) wattron(stdscr, A_DIM); if (sc.dim) wattron(stdscr, A_DIM);
if (sc.bold) wattron(stdscr, A_BOLD); if (sc.bold) wattron(stdscr, A_BOLD);
if (sc.underline) wattron(stdscr, A_UNDERLINE); if (sc.underline) wattron(stdscr, A_UNDERLINE);
(void)mvwaddstr(stdscr, y+(int)(sheet->oriy), (void)mvwaddstr(stdscr, (int)(height + sheet->oriy),
(int)(sheet->orix + width), (int)(width + sheet->orix),
buf+cutoff); buf+cutoff);
for (fill=mbslen(buf+cutoff); fill<realsize; ++fill) for (fill=mbslen(buf+cutoff); fill<realsize; ++fill)
(void)waddch(stdscr,(chtype)(unsigned char)' '); (void)waddch(stdscr,(chtype)(unsigned char)' ');
for (RowHgtT extra = 1; extra < rows; ++extra) {
mvwaddstr(stdscr,
(int)(height + extra + sheet->oriy),
(int)(width + sheet->orix),
" ");
for (fill = 1; fill < realsize; ++fill)
(void)waddch(stdscr, (chtype)(unsigned char)' ');
}
wcolor_set(stdscr, 0, NULL); wcolor_set(stdscr, 0, NULL);
wstandend(stdscr); wstandend(stdscr);
} }
}
height += rows;
} }
/* draw contents of current element */ /* draw contents of current element */
@ -596,11 +638,11 @@ void redraw_sheet(Sheet *sheet)
FLT_COMPACT, -1, TRUNCATED_ERROR, &ic); FLT_COMPACT, -1, TRUNCATED_ERROR, &ic);
} }
} }
*mbspos(buf, sheet->maxx) = 0; *mbspos(buf, (int)sheet->maxx) = 0;
(void)mvwaddstr(stdscr, (int)(sheet->oriy) + sheet->maxy - 1, (void)mvwaddstr(stdscr, (int)(sheet->oriy + sheet->maxy) - 1,
(int)(sheet->orix), buf); (int)(sheet->orix), buf);
for (col = mbslen(buf); col < (size_t)sheet->maxx; ++col) for (size_t col = mbslen(buf); col < sheet->maxx; ++col)
(void)waddch(stdscr, ' '); (void)waddch(stdscr, ' ');
} }

View File

@ -41,6 +41,7 @@ class TeapotTable {open : {public Fl_Table}}
{ {
decl {Sheet *cursheet;} {protected local} decl {Sheet *cursheet;} {protected local}
decl {bool cut, updating;} {protected local} decl {bool cut, updating;} {protected local}
decl {int unit_width, unit_height;} {protected local}
decl {static const TableContext ACTION = (TableContext)(1<<8);} decl {static const TableContext ACTION = (TableContext)(1<<8);}
{public local} {public local}
decl {static const TableContext REFRESH = (TableContext)(1<<9);} decl {static const TableContext REFRESH = (TableContext)(1<<9);}
@ -48,14 +49,25 @@ class TeapotTable {open : {public Fl_Table}}
Function Function
{TeapotTable(int x, int y, int w, int h, const char *l=0) : {TeapotTable(int x, int y, int w, int h, const char *l=0) :
Fl_Table(x, y, w, h, l), cut(false), updating(false)} {open} {code Fl_Table(x, y, w, h, l), cut(false), updating(false),
unit_width(10), unit_height(0)} {open} {code
{ {
end(); end();
col_resize_min(10); col_resize_min(unit_width);
col_resize(true); col_resize(true);
col_header(header); col_header(header);
row_resize(false); unit_height = fl_height(FL_HELVETICA, fontsize);
col_header_height(unit_height);
fl_font(FL_HELVETICA, fontsize);
int ww = 0, hh = 0;
fl_measure("8888", ww, hh, 0);
int min_row_height = (unit_height + ROWHEIGHT_DENOMINATOR/2 - 1)
/ ROWHEIGHT_DENOMINATOR;
if (min_row_height < 1) min_row_height = 1;
row_resize_min(min_row_height);
row_resize(true);
row_header(header); row_header(header);
row_header_width(ww + unit_width);
set_visible_focus(); set_visible_focus();
table_box(FL_THIN_UP_FRAME); table_box(FL_THIN_UP_FRAME);
} {} } } {} }
@ -92,7 +104,7 @@ class TeapotTable {open : {public Fl_Table}}
case CONTEXT_ENDPAGE: case CONTEXT_ENDPAGE:
W = xx-x()-2; H = yy-y()-2; W = xx-x()-2; H = yy-y()-2;
xx = x()+2; yy = y()+2; xx = x()+2; yy = y()+2;
fl_font(FL_HELVETICA | FL_BOLD, 14); fl_font(FL_HELVETICA | FL_BOLD, fontsize);
fl_push_clip(xx, yy, W, H); fl_push_clip(xx, yy, W, H);
fl_draw_box(FL_DIAMOND_UP_BOX, xx, yy, W, H, col_header_color()); fl_draw_box(FL_DIAMOND_UP_BOX, xx, yy, W, H, col_header_color());
fl_color(FL_INACTIVE_COLOR); fl_color(FL_INACTIVE_COLOR);
@ -107,7 +119,7 @@ class TeapotTable {open : {public Fl_Table}}
break; break;
case CONTEXT_COL_HEADER: { case CONTEXT_COL_HEADER: {
fl_font(FL_HELVETICA | FL_BOLD, 14); fl_font(FL_HELVETICA | FL_BOLD, fontsize);
fl_push_clip(xx, yy, W, H); fl_push_clip(xx, yy, W, H);
Fl_Color hd_clr = col_header_color(); Fl_Color hd_clr = col_header_color();
if (C == cursheet->cur[X]) hd_clr = tpt_selection_version(hd_clr); if (C == cursheet->cur[X]) hd_clr = tpt_selection_version(hd_clr);
@ -120,7 +132,7 @@ class TeapotTable {open : {public Fl_Table}}
} }
case CONTEXT_ROW_HEADER: { case CONTEXT_ROW_HEADER: {
fl_font(FL_HELVETICA | FL_BOLD, 14); fl_font(FL_HELVETICA | FL_BOLD, fontsize);
fl_push_clip(xx, yy, W, H); fl_push_clip(xx, yy, W, H);
Fl_Color hd_clr = row_header_color(); Fl_Color hd_clr = row_header_color();
if (R == cursheet->cur[Y]) hd_clr = tpt_selection_version(hd_clr); if (R == cursheet->cur[Y]) hd_clr = tpt_selection_version(hd_clr);
@ -171,7 +183,7 @@ class TeapotTable {open : {public Fl_Table}}
Fl_Font cellfont = FL_HELVETICA; Fl_Font cellfont = FL_HELVETICA;
if (sc.bold) cellfont |= FL_BOLD; if (sc.bold) cellfont |= FL_BOLD;
if (sc.italic) cellfont |= FL_ITALIC; if (sc.italic) cellfont |= FL_ITALIC;
fl_font(cellfont, 14); fl_font(cellfont, fontsize);
size_t ulen = printvalue(s, sizeof(s), 0, quote, sc.fform, size_t ulen = printvalue(s, sizeof(s), 0, quote, sc.fform,
sc.precision, cursheet, test); sc.precision, cursheet, test);
@ -216,21 +228,29 @@ class TeapotTable {open : {public Fl_Table}}
{ {
if (updating) return; if (updating) return;
updating = true; updating = true;
if (debug_level > 2) if (debug_level > 1)
printf("update_table: %zux%zu@%i,%i; %i[%i], %i[%i]\\n", printf("update_table: %zux%zu@%i,%i; %i[%lu], %i[%lu]\\n",
cursheet->dim[X], cursheet->dim[Y], cursheet->dim[X], cursheet->dim[Y],
cursheet->cur[X], cursheet->cur[Y], cursheet->cur[X], cursheet->cur[Y],
cursheet->offx, cursheet->maxx, cursheet->offx, cursheet->maxx,
cursheet->offy, cursheet->maxy); cursheet->offy, cursheet->maxy);
bool no_table = (cols() == 0) || (rows() == 0);
if (cursheet->dim[X] > (size_t)cols()) cols(cursheet->dim[X]); if (cursheet->dim[X] > (size_t)cols()) cols(cursheet->dim[X]);
if (no_table) col_width_all(DEF_COLUMNWIDTH*unit_width);
if (cursheet->dim[Y] > (size_t)rows()) rows(cursheet->dim[Y]); if (cursheet->dim[Y] > (size_t)rows()) rows(cursheet->dim[Y]);
if (no_table) row_height_all(unit_height);
adjust_outside(); adjust_outside();
for (int x = 0; (size_t)x < cursheet->dim[X]; x++) { for (int x = 0; (size_t)x < cursheet->dim[X]; x++) {
int w = columnwidth(cursheet, x, cursheet->cur[Z])*10; int w = columnwidth(cursheet, x, cursheet->cur[Z])*unit_width;
if (col_width(x) != w) col_width(x, w); if (col_width(x) != w) col_width(x, w);
} }
for (int y = 0; (size_t)y < cursheet->dim[Y]; ++y) {
int h = rowheight(cursheet, y, cursheet->cur[Z])*unit_height
/ ROWHEIGHT_DENOMINATOR;
if (row_height(y) != h) row_height(y, h);
}
col_position(cursheet->offx); col_position(cursheet->offx);
row_position(cursheet->offy); row_position(cursheet->offy);
set_selection(cursheet->cur[Y], cursheet->cur[X], set_selection(cursheet->cur[Y], cursheet->cur[X],
@ -257,25 +277,34 @@ class TeapotTable {open : {public Fl_Table}}
cursheet->marking = MARKED; cursheet->marking = MARKED;
} }
moveto(cursheet, current_col, current_row, -1); moveto(cursheet, current_col, current_row, -1);
visible_cells(cursheet->offy, cursheet->maxy, int lastx, lasty;
cursheet->offx, cursheet->maxx); visible_cells(cursheet->offy, lasty,
cursheet->maxx -= cursheet->offx; cursheet->offx, lastx);
cursheet->maxy -= cursheet->offy; cursheet->maxx = (size_t)(lastx - cursheet->offx);
cursheet->maxy = (size_t)(lasty - cursheet->offy);
if (is_interactive_resize()) { if (is_interactive_resize()) {
for (size_t C = 0; C < cursheet->dim[X]; ++C) { for (size_t C = 0; C < cursheet->dim[X]; ++C) {
size_t w = (col_width(C) + 5)/10; size_t w = (col_width(C) + unit_width/2)/unit_width;
if (w != columnwidth(cursheet, C, cursheet->cur[Z])) if (w != columnwidth(cursheet, C, cursheet->cur[Z]))
setwidth(cursheet, C, cursheet->cur[Z], w); setwidth(cursheet, C, cursheet->cur[Z], w);
} }
for (size_t R = 0; R < cursheet->dim[Y]; ++R) {
size_t h =
(row_height(R)*ROWHEIGHT_DENOMINATOR + unit_height/2)
/ unit_height;
if (h != rowheight(cursheet, R, cursheet->cur[Z]))
setheight(cursheet, R, cursheet->cur[Z], h);
}
} }
updating = false; updating = false;
if (debug_level > 2) if (debug_level > 1)
printf("upd_sheet: %ix%i@%i,%i; %i[%i], %i[%i] (%i,%i)-(%i,%i)\\n", printf(
cols(), rows(), cursheet->cur[X], cursheet->cur[Y], "upd_sheet: %ix%i@%i,%i; %i[%lu], %i[%lu] (%i,%i)-(%i,%i)\\n",
cursheet->offx, cursheet->maxx, cols(), rows(), cursheet->cur[X], cursheet->cur[Y],
cursheet->offy, cursheet->maxy, x1, y1, x2, y2); cursheet->offx, cursheet->maxx,
cursheet->offy, cursheet->maxy, x1, y1, x2, y2);
} {} } } {} }
Function Function
@ -399,7 +428,7 @@ class TeapotTable {open : {public Fl_Table}}
if (!cols() || !rows()) { cols(1); rows(1); } if (!cols() || !rows()) { cols(1); rows(1); }
visible_cells(y1, y2, x1, x2); visible_cells(y1, y2, x1, x2);
if (debug_level > 2) if (debug_level > 1)
printf("adj: (%i,%i)-(%i,%i) %ix%i\\n", x1, y1, x2, y2, printf("adj: (%i,%i)-(%i,%i) %ix%i\\n", x1, y1, x2, y2,
cols(), rows()); cols(), rows());
if (x2+2 < cols() && (size_t)cols() > cursheet->dim[X]) if (x2+2 < cols() && (size_t)cols() > cursheet->dim[X])