ref: ef1c78b3ad619f48c4835f1684cf23393d704b3b
parent: 02f0fdccefc6d03202d5c631141b8b0dc951f775
author: glenda <glenda@krsna>
date: Sun Aug 17 17:14:04 EDT 2025
really-done-now
--- a/fc.c
+++ b/fc.c
@@ -396,36 +396,36 @@
};
BoxType boxtypes[] = {
- [T_TEXT] = {"text", parse_text, eval_text, draw_box_generic},
+ [T_TEXT] = {"text", parse_text, eval_text, draw_box_generic},
[T_NUMBER] = {"number", parse_number, eval_number, draw_box_generic},
[T_FORMULA] = {"formula", parse_formula, eval_formula, draw_box_generic},
- [T_LABEL] = {"label", parse_text, eval_text, draw_box_generic},
+ [T_LABEL] = {"label", parse_text, eval_text, draw_box_generic},
[T_PARAGRAPH] = {"paragraph", parse_paragraph, eval_paragraph, draw_box_paragraph},
};
Function functions[MAXFUNCS] = {
- [FN_SUM] = {"SUM", 1, 100, fn_sum},
- [FN_AVG] = {"AVG", 1, 100, fn_avg},
- [FN_MIN] = {"MIN", 1, 100, fn_min},
- [FN_MAX] = {"MAX", 1, 100, fn_max},
+ [FN_SUM] = {"SUM", 1, 100, fn_sum},
+ [FN_AVG] = {"AVG", 1, 100, fn_avg},
+ [FN_MIN] = {"MIN", 1, 100, fn_min},
+ [FN_MAX] = {"MAX", 1, 100, fn_max},
[FN_COUNT] = {"COUNT", 1, 100, fn_count},
- [FN_ABS] = {"ABS", 1, 1, fn_abs},
+ [FN_ABS] = {"ABS", 1, 1, fn_abs},
[FN_SQRT] = {"SQRT", 1, 1, fn_sqrt},
- [FN_POW] = {"POW", 2, 2, fn_pow},
+ [FN_POW] = {"POW", 2, 2, fn_pow},
[FN_ROUND] = {"ROUND", 1, 2, fn_round},
[FN_FLOOR] = {"FLOOR", 1, 1, fn_floor},
[FN_CEIL] = {"CEIL", 1, 1, fn_ceil},
- [FN_IF] = {"IF", 3, 3, fn_if},
- [FN_AND] = {"AND", 2, 100, fn_and},
- [FN_OR] = {"OR", 2, 100, fn_or},
- [FN_NOT] = {"NOT", 1, 1, fn_not},
+ [FN_IF] = {"IF", 3, 3, fn_if},
+ [FN_AND] = {"AND", 2, 100, fn_and},
+ [FN_OR] = {"OR", 2, 100, fn_or},
+ [FN_NOT] = {"NOT", 1, 1, fn_not},
[FN_LOOKUP] = {"LOOKUP", 2, 3, fn_lookup},
};
InputMode input_modes[] = {
- [0] = {"normal", handle_normal_mode, handle_normal_mouse, draw_normal_overlay, "E:moji e:cycle S:ave O:pen l:abel g:rid r:eload-cfg "},
- [1] = {"edit", handle_cell_edit, handle_edit_mouse, draw_cell_edit_overlay, "Enter:save Esc:cancel"},
- [2] = {"label", handle_label_edit, handle_label_mouse, draw_label_edit_overlay,"Enter:save Esc:cancel"},
+ [0] = {"normal", handle_normal_mode, handle_normal_mouse, draw_normal_overlay, "E:moji e:cycle S:ave O:pen l:abel g:rid r:eload-cfg "},
+ [1] = {"edit", handle_cell_edit, handle_edit_mouse, draw_cell_edit_overlay, "Enter:save Esc:cancel"},
+ [2] = {"label", handle_label_edit, handle_label_mouse, draw_label_edit_overlay,"Enter:save Esc:cancel"},
[3] = {"filename", handle_filename_input, handle_filename_mouse, draw_filename_overlay, "Tab:.spr Enter:confirm Esc:cancel"},
};
@@ -539,8 +539,12 @@
Bprint(b, "box %d\n", i);
Bprint(b, " pos %d %d\n", box->pos.x, box->pos.y);
Bprint(b, " type %d\n", box->type);
+
+ Bprint(b, " formula_len %d\n", (int)strlen(box->formula));
Bprint(b, " formula %s\n", box->formula);
+
Bprint(b, " value %g\n", box->value);
+ Bprint(b, " label_len %d\n", (int)strlen(box->label));
Bprint(b, " label %s\n", box->label);
if(box->nrefs > 0){
@@ -563,6 +567,8 @@
char *line;
char *fields[10];
int nf;
+ int formula_len = 0;
+ int label_len = 0;
b = Bopen(file, OREAD);
if(b == nil){
@@ -586,6 +592,44 @@
if(line[0] == '#' || line[0] == '\0')
continue;
+ // Check for formula with spaces (don't tokenize these lines)
+ if(strncmp(line, " formula ", 10) == 0){
+ if(sheet.nboxes > 0){
+ Box *box = &sheet.boxes[sheet.nboxes-1];
+ char *content = line + 10;
+
+ // If we have a length, use it; otherwise just copy what's there
+ if(formula_len > 0 && formula_len < MAXFORMULA){
+ strncpy(box->formula, content, formula_len);
+ box->formula[formula_len] = '\0';
+ formula_len = 0;
+ } else {
+ strncpy(box->formula, content, MAXFORMULA-1);
+ box->formula[MAXFORMULA-1] = '\0';
+ }
+ }
+ continue;
+ }
+
+ // Check for label with spaces
+ if(strncmp(line, " label ", 8) == 0){
+ if(sheet.nboxes > 0){
+ Box *box = &sheet.boxes[sheet.nboxes-1];
+ char *content = line + 8;
+
+ if(label_len > 0 && label_len < 32){
+ strncpy(box->label, content, label_len);
+ box->label[label_len] = '\0';
+ label_len = 0;
+ } else {
+ strncpy(box->label, content, 31);
+ box->label[31] = '\0';
+ }
+ }
+ continue;
+ }
+
+ // For other lines, use tokenize as before
nf = tokenize(line, fields, nelem(fields));
if(nf >= 2 && strcmp(fields[0], "box") == 0){
@@ -604,16 +648,22 @@
} else if(nf >= 2 && strcmp(fields[0], "type") == 0){
int type = atoi(fields[1]);
if (type >= 0 && type < MAXBOXTYPES) {
- sheet.boxes[sheet.nboxes-1].type = type;
- } else {
- sheet.boxes[sheet.nboxes-1].type = T_TEXT;
+ Box *box = &sheet.boxes[sheet.nboxes-1];
+ box->type = type;
+
+ // Resize box if it's a paragraph
+ if(type == T_PARAGRAPH){
+ box->r = Rect(box->pos.x, box->pos.y,
+ box->pos.x + config.paragraph_width,
+ box->pos.y + config.paragraph_height);
+ }
}
- } else if(nf >= 2 && strcmp(fields[0], "formula") == 0){
- strcpy(sheet.boxes[sheet.nboxes-1].formula, fields[1]);
+ } else if(nf >= 2 && strcmp(fields[0], "formula_len") == 0){
+ formula_len = atoi(fields[1]);
+ } else if(nf >= 2 && strcmp(fields[0], "label_len") == 0){
+ label_len = atoi(fields[1]);
} else if(nf >= 2 && strcmp(fields[0], "value") == 0){
sheet.boxes[sheet.nboxes-1].value = atof(fields[1]);
- } else if(nf >= 2 && strcmp(fields[0], "label") == 0){
- strncpy(sheet.boxes[sheet.nboxes-1].label, fields[1], 31);
}
}
@@ -925,32 +975,6 @@
}
void
-cmd_reload_config(void)
-{
- load_config(CONFIG_FILE);
- validate_config();
- apply_config();
- sheet.needredraw = 1;
- fprint(2, "Configuration reloaded from %s\n", CONFIG_FILE);
-}
-
-void
-handlekey(int key)
-{
- InputMode *mode = &input_modes[sheet.current_mode];
- if(mode->handler)
- mode->handler(key);
-}
-
-void
-handlemouse(Mouse m)
-{
- InputMode *mode = &input_modes[sheet.current_mode];
- if(mode->mouse_handler)
- mode->mouse_handler(m);
-}
-
-void
initcolors(void)
{
colors[0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, config.color_fg);
@@ -966,6 +990,19 @@
gridcolor = allocimage(display, Rect(0,0,1,1), screen->chan, 1, config.color_grid);
}
+void
+init_emoji(void)
+{
+ sheet.emoji_pos = 0;
+ sheet.emoji_frame = 0;
+ sheet.emoji_dir = 1;
+ sheet.emoji_enabled = config.emoji_enabled;
+
+ int i;
+ for(i = 0; i < 4; i++)
+ sheet.emoji_frames[i] = rcc_style[i];
+}
+
double
round(double x)
{
@@ -1743,6 +1780,17 @@
}
void
+parse_paragraph(Box *b)
+{
+ if(b->formula[0] == '"'){
+ strncpy(b->content, b->formula + 1, MAXCONTENT - 1);
+ } else {
+ strncpy(b->content, b->formula, MAXCONTENT - 1);
+ }
+ b->content[MAXCONTENT-1] = '\0';
+}
+
+void
parse_text(Box *b)
{
strncpy(b->content, b->formula, MAXCONTENT);
@@ -1769,6 +1817,12 @@
}
void
+eval_paragraph(Box *b)
+{
+ USED(b);
+}
+
+void
draw_box_generic(Box *b, Image *dst)
{
Image *bg = boxbg;
@@ -1917,50 +1971,6 @@
}
void
-redraw(void)
-{
- DrawStep *step;
- draw_emoji_banner();
- Rectangle clip = screen->r;
- clip.min.y += config.banner_height;
- replclipr(screen, 0, clip);
-
- for(step = draw_steps; step->draw; step++) {
- if(step->condition == 0 ||
- (step->condition == 1 && sheet.gridsnap)) {
- step->draw();
- }
- }
- replclipr(screen, 0, screen->r);
-
- InputMode *mode = &input_modes[sheet.current_mode];
- if(mode->draw)
- mode->draw();
-
- flushimage(display, 1);
-}
-
-int
-edit_finish(char *buf, int *pos, int maxlen)
-{
- USED(buf); USED(pos); USED(maxlen);
- return 1;
-}
-
-void
-init_emoji(void)
-{
- sheet.emoji_pos = 0;
- sheet.emoji_frame = 0;
- sheet.emoji_dir = 1;
- sheet.emoji_enabled = config.emoji_enabled;
-
- int i;
- for(i = 0; i < 4; i++)
- sheet.emoji_frames[i] = rcc_style[i];
-}
-
-void
draw_emoji_banner(void)
{
if(!sheet.emoji_enabled)
@@ -2001,12 +2011,165 @@
}
void
+draw_box_paragraph(Box *b, Image *dst)
+{
+ Image *bg = boxbg;
+ int idx = b - sheet.boxes;
+
+ /* Determine background color based on state (editing, selected) */
+ if(sheet.editing == idx)
+ bg = boxediting;
+ else if(sheet.editing_label == idx)
+ bg = colors[5];
+ else if(b->selected)
+ bg = boxselected;
+
+ /* Draw box background and border */
+ draw(dst, b->r, bg, nil, ZP);
+ border(dst, b->r, 1, colors[0], ZP);
+
+ /* Draw the cell's label or default name */
+ char cellname[32];
+ if(sheet.editing_label == idx){
+ snprint(cellname, sizeof(cellname), "%s", sheet.labelbuf);
+ string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[4], ZP, font, cellname);
+ } else if(b->label[0]) {
+ snprint(cellname, sizeof(cellname), "%s", b->label);
+ string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[4], ZP, font, cellname);
+ } else {
+ if(idx < 26) {
+ snprint(cellname, sizeof(cellname), "%c", 'A' + idx);
+ } else {
+ snprint(cellname, sizeof(cellname), "%c%c", 'A' + (idx/26)-1, 'A' + (idx%26));
+ }
+ string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[3], ZP, font, cellname);
+ }
+
+ /* Text wrapping logic */
+ Point p = addpt(b->r.min, Pt(config.box_text_margin, config.box_label_offset_y));
+ char *text_to_draw = (sheet.editing == idx) ? sheet.editbuf : b->content;
+ int max_width = Dx(b->r) - (2 * config.box_text_margin);
+ int line_height = font->height;
+
+ char *text = text_to_draw;
+ char *line_start = text;
+ char line_buffer[MAXCONTENT];
+
+ while (*line_start) {
+ char *word_ptr = line_start;
+ char *line_end = line_start;
+
+ while (*word_ptr) {
+ char *word_start = word_ptr;
+ while(*word_ptr && !isspace(*word_ptr))
+ word_ptr++;
+
+ int word_len = word_ptr - line_start;
+ if(word_len >= MAXCONTENT) break;
+
+ strncpy(line_buffer, line_start, word_len);
+ line_buffer[word_len] = '\0';
+
+ if(stringwidth(font, line_buffer) > max_width) {
+ if(line_end == line_start)
+ line_end = word_start;
+ break;
+ }
+ line_end = word_ptr;
+
+ while(*word_ptr && isspace(*word_ptr))
+ word_ptr++;
+ }
+
+ int len = line_end - line_start;
+ stringn(dst, p, colors[0], ZP, font, line_start, len);
+ p.y += line_height;
+
+ if (p.y > b->r.max.y - config.box_text_margin - line_height)
+ break;
+
+ line_start = line_end;
+ while(*line_start && isspace(*line_start))
+ line_start++;
+ }
+}
+
+void
+redraw(void)
+{
+ DrawStep *step;
+ draw_emoji_banner();
+ Rectangle clip = screen->r;
+ clip.min.y += config.banner_height;
+ replclipr(screen, 0, clip);
+
+ for(step = draw_steps; step->draw; step++) {
+ if(step->condition == 0 ||
+ (step->condition == 1 && sheet.gridsnap)) {
+ step->draw();
+ }
+ }
+ replclipr(screen, 0, screen->r);
+
+ InputMode *mode = &input_modes[sheet.current_mode];
+ if(mode->draw)
+ mode->draw();
+
+ flushimage(display, 1);
+}
+
+int
+edit_cancel(char *buf, int *pos, int maxlen)
+{
+ USED(maxlen);
+ buf[0] = '\0';
+ *pos = 0;
+ return -1;
+}
+
+int
+edit_backspace(char *buf, int *pos, int maxlen)
+{
+ USED(maxlen);
+ if(*pos > 0) {
+ (*pos)--;
+ buf[*pos] = '\0';
+ sheet.needredraw = 1;
+ }
+ return 0;
+}
+
+int
+edit_add_char(char *buf, int *pos, int maxlen)
+{
+ USED(buf); USED(pos); USED(maxlen);
+ return 0;
+}
+
+int
+edit_finish(char *buf, int *pos, int maxlen)
+{
+ USED(buf); USED(pos); USED(maxlen);
+ return 1;
+}
+
+void
+cmd_reload_config(void)
+{
+ load_config(CONFIG_FILE);
+ validate_config();
+ apply_config();
+ sheet.needredraw = 1;
+ fprint(2, "Configuration reloaded from %s\n", CONFIG_FILE);
+}
+
+void
cmd_cycle_emoji(void)
{
static int emoji_set = 0;
int i;
- emoji_set = (emoji_set + 1) % 7;
+ emoji_set = (emoji_set + 1) % 7; /* +1 each case */
switch(emoji_set) {
case 0:
@@ -2042,42 +2205,6 @@
}
void
-cmd_toggle_emoji(void)
-{
- sheet.emoji_enabled = !sheet.emoji_enabled;
- config.emoji_enabled = sheet.emoji_enabled;
- sheet.needredraw = 1;
-}
-
-int
-edit_cancel(char *buf, int *pos, int maxlen)
-{
- USED(maxlen);
- buf[0] = '\0';
- *pos = 0;
- return -1;
-}
-
-int
-edit_backspace(char *buf, int *pos, int maxlen)
-{
- USED(maxlen);
- if(*pos > 0) {
- (*pos)--;
- buf[*pos] = '\0';
- sheet.needredraw = 1;
- }
- return 0;
-}
-
-int
-edit_add_char(char *buf, int *pos, int maxlen)
-{
- USED(buf); USED(pos); USED(maxlen);
- return 0;
-}
-
-void
cmd_quit(void)
{
int i;
@@ -2165,6 +2292,30 @@
}
void
+cmd_toggle_emoji(void)
+{
+ sheet.emoji_enabled = !sheet.emoji_enabled;
+ config.emoji_enabled = sheet.emoji_enabled;
+ sheet.needredraw = 1;
+}
+
+void
+handlekey(int key)
+{
+ InputMode *mode = &input_modes[sheet.current_mode];
+ if(mode->handler)
+ mode->handler(key);
+}
+
+void
+handlemouse(Mouse m)
+{
+ InputMode *mode = &input_modes[sheet.current_mode];
+ if(mode->mouse_handler)
+ mode->mouse_handler(m);
+}
+
+void
handle_normal_mode(int key)
{
Command *cmd;
@@ -2482,107 +2633,6 @@
fd = create(config.ctl_file, OWRITE, 0644);
if(fd >= 0) close(fd);
-}
-
-void
-parse_paragraph(Box *b)
-{
- if(b->formula[0] == '"'){
- strncpy(b->content, b->formula + 1, MAXCONTENT - 1);
- } else {
- strncpy(b->content, b->formula, MAXCONTENT - 1);
- }
- b->content[MAXCONTENT-1] = '\0';
-}
-
-void
-eval_paragraph(Box *b)
-{
- USED(b);
-}
-
-void
-draw_box_paragraph(Box *b, Image *dst)
-{
- Image *bg = boxbg;
- int idx = b - sheet.boxes;
-
- /* Determine background color based on state (editing, selected) */
- if(sheet.editing == idx)
- bg = boxediting;
- else if(sheet.editing_label == idx)
- bg = colors[5];
- else if(b->selected)
- bg = boxselected;
-
- /* Draw box background and border */
- draw(dst, b->r, bg, nil, ZP);
- border(dst, b->r, 1, colors[0], ZP);
-
- /* Draw the cell's label or default name */
- char cellname[32];
- if(sheet.editing_label == idx){
- snprint(cellname, sizeof(cellname), "%s", sheet.labelbuf);
- string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[4], ZP, font, cellname);
- } else if(b->label[0]) {
- snprint(cellname, sizeof(cellname), "%s", b->label);
- string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[4], ZP, font, cellname);
- } else {
- if(idx < 26) {
- snprint(cellname, sizeof(cellname), "%c", 'A' + idx);
- } else {
- snprint(cellname, sizeof(cellname), "%c%c", 'A' + (idx/26)-1, 'A' + (idx%26));
- }
- string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[3], ZP, font, cellname);
- }
-
- /* Text wrapping logic */
- Point p = addpt(b->r.min, Pt(config.box_text_margin, config.box_label_offset_y));
- char *text_to_draw = (sheet.editing == idx) ? sheet.editbuf : b->content;
- int max_width = Dx(b->r) - (2 * config.box_text_margin);
- int line_height = font->height;
-
- char *text = text_to_draw;
- char *line_start = text;
- char line_buffer[MAXCONTENT];
-
- while (*line_start) {
- char *word_ptr = line_start;
- char *line_end = line_start;
-
- while (*word_ptr) {
- char *word_start = word_ptr;
- while(*word_ptr && !isspace(*word_ptr))
- word_ptr++;
-
- int word_len = word_ptr - line_start;
- if(word_len >= MAXCONTENT) break;
-
- strncpy(line_buffer, line_start, word_len);
- line_buffer[word_len] = '\0';
-
- if(stringwidth(font, line_buffer) > max_width) {
- if(line_end == line_start)
- line_end = word_start;
- break;
- }
- line_end = word_ptr;
-
- while(*word_ptr && isspace(*word_ptr))
- word_ptr++;
- }
-
- int len = line_end - line_start;
- stringn(dst, p, colors[0], ZP, font, line_start, len);
- p.y += line_height;
-
- if (p.y > b->r.max.y - config.box_text_margin - line_height)
- break;
-
- line_start = line_end;
- while(*line_start && isspace(*line_start))
- line_start++;
- }
}
void
--
⑨