teapot-spreadsheet/fteapot.fl
Glen Whitney 08b42bf424 Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
  short-cutting in getvalue() when the contents of a cell were empty,
  preventing the update of the internal cache of the value of the cell.

  However, tracking this down (and getting the associated memory management
  correct) necessitated implementing a debugging mode in which I could
  dump the internal states of cells and print various other stuff to standard
  output. It also involved understanding the meaning of various pointers in
  the code, in the process of which I renamed some commonly used macros,
  particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
  all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
  also replaced several very repeatedly used patterns of checking the validity
  of locations and pointers with macros, now defined in sheet.h.

  Therefore, unfortunately the (relatively small in the end) bugfix for this
  major issue is entangled with numerous textual changes to the code made
  in tracking it down.
  Fixes #18.
  Closes #19.
2019-07-24 10:47:39 -07:00

852 lines
23 KiB
Plaintext

# data file for the Fltk User Interface Designer (fluid)
version 1.0300
header_name {.h}
code_name {.cxx}
decl {\#include <unistd.h>} {private global
}
decl {\#include <stdint.h>} {private global
}
decl {\#include <limits.h>} {private global
}
decl {\#include <fcntl.h>} {private global
}
decl {\#define shadow _shadow} {private global
}
decl {\#define transparent _transparent} {private global
}
decl {\#define MenuChoice _MenuChoice} {private global
}
decl {\#define Cell _Cell} {private global
}
decl {\#include <FL/fl_message.H>} {private local
}
decl {\#include <FL/fl_draw.H>} {private global
}
decl {\#include <FL/Fl_Native_File_Chooser.H>} {private global
}
decl {\#include <FL/Fl_File_Icon.H>} {private global
}
decl {\#include <FL/filename.H>} {private global
}
decl {\#include <FL/Fl_Table.H>} {public global
}
decl {\#include <FL/Fl_Select_Browser.H>} {public global
}
decl {\#include <FL/Fl_Sys_Menu_Bar.H>} {public global
}
decl {\#undef shadow} {private global
}
decl {\#undef transparent} {private global
}
decl {\#undef MenuChoice} {private global
}
decl {\#undef Cell} {private global
}
decl {\#include "misc.h"} {private global
}
decl {\#include "display.h"} {public global
}
class TeapotTable {open : {public Fl_Table}
} {
decl {Sheet *cursheet;} {protected local
}
decl {bool cut, updating;} {protected local
}
decl {static const TableContext ACTION = (TableContext)(1<<8);} {public local
}
decl {static const TableContext REFRESH = (TableContext)(1<<9);} {public local
}
Function {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 {end();
col_resize_min(10);
col_resize(true);
col_header(header);
row_resize(false);
row_header(header);
set_visible_focus();
table_box(FL_THIN_UP_FRAME);} {}
}
Function {~TeapotTable()} {} {
code {} {}
}
Function {sheet(Sheet *s)} {open return_type void
} {
code {cursheet = s;
s->display = (void *)this;
clear();
update_table();
do_callback(CONTEXT_NONE, 0, 0);} {}
}
Function {sheet()} {return_type {Sheet *}
} {
code {return cursheet;} {}
}
Function {draw_cell(TableContext context, int R, int C, int X, int Y, int W, int H)} {open return_type void
} {
code {char s[1024];
//printf("DRAW: %i @%i,%i - (%i,%i) %ix%i\\n", context, C,R, X,Y, W,H);
switch (context) {
case CONTEXT_ENDPAGE:
W = X-x()-2;
H = Y-y()-2;
X = x()+2;
Y = y()+2;
fl_font(FL_HELVETICA | FL_BOLD, 14);
fl_push_clip(X, Y, W, H);
fl_draw_box(FL_DIAMOND_UP_BOX, X, Y, W, H, col_header_color());
fl_color(FL_INACTIVE_COLOR);
sprintf(s, "%d", cursheet->curz);
fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
fl_pop_clip();
break;
case CONTEXT_STARTPAGE:
adjust_outside();
if (Fl::event_button1()) update_sheet();
break;
case CONTEXT_COL_HEADER:
fl_font(FL_HELVETICA | FL_BOLD, 14);
fl_push_clip(X, Y, W, H);
fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, col_header_color());
fl_color(FL_FOREGROUND_COLOR);
sprintf(s, "%d", C);
fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
fl_pop_clip();
return;
case CONTEXT_ROW_HEADER:
fl_font(FL_HELVETICA | FL_BOLD, 14);
fl_push_clip(X, Y, W, H);
fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, row_header_color());
fl_color(FL_FOREGROUND_COLOR);
sprintf(s, "%d", R);
fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
fl_pop_clip();
return;
case CONTEXT_CELL: {
while (SHADOWED(cursheet, C, R, cursheet->curz)) X -= W = col_width(--C);
int x = C+1;
while (SHADOWED(cursheet,x,R,cursheet->curz)) W += col_width(x), x++;
fl_push_clip(X, Y, W, H);
bool selected = false;
if (cursheet->mark1x >= 0) {
int x1 = cursheet->mark1x, x2 = cursheet->mark2x, y1 = cursheet->mark1y, y2 = cursheet->mark2y, z1 = cursheet->mark1z, z2 = cursheet->mark2z;
posorder(&x1, &x2);
posorder(&y1, &y2);
posorder(&z1, &z2);
selected = cursheet->mark1x >= 0 && C >= x1 && C <= x2 && R >= y1 && R <= y2 && cursheet->curz >= z1 && cursheet->curz <= z2;
}
fl_draw_box(C == cursheet->curx && R == cursheet->cury?FL_BORDER_BOX:FL_THIN_DOWN_BOX, X, Y, W, H, selected?FL_SELECTION_COLOR:FL_BACKGROUND2_COLOR);
if (Fl::focus() == this && C == cursheet->curx && R == cursheet->cury) draw_focus(FL_BORDER_BOX, X, Y, W, H);
fl_pop_clip();
fl_push_clip(X+3, Y+3, W-6, H-6);
fl_color(FL_FOREGROUND_COLOR);
fl_font(FL_HELVETICA | (isbold(cursheet, C, R, cursheet->curz)? FL_BOLD:0), 14);
printvalue(s, sizeof(s), 0, 0, getscientific(cursheet, C, R, cursheet->curz), getprecision(cursheet, C, R, cursheet->curz), cursheet, C, R, cursheet->curz);
int ww = 0, hh = 0;
fl_measure(s, ww, hh, 0);
if (ww > W-6) for (int i = 0; s[i]; i++) s[i] = '\#';
int adj = getadjust(cursheet, C, R, cursheet->curz);
fl_draw(s, X+3, Y+3, W-6, H-6, adj == RIGHT?FL_ALIGN_RIGHT:adj == LEFT?FL_ALIGN_LEFT:FL_ALIGN_CENTER);
if (underlined(cursheet, C, R, cursheet->curz)) fl_xyline(X, Y+H-7, X+W);
fl_pop_clip();
return;
}
default:
return;
}} {selected
}
}
Function {update_table()} {open return_type void
} {
code {if (updating) return;
updating = true;
//printf("update_table: %ix%i@%i,%i; %i[%i], %i[%i]\\n", cursheet->dimx, cursheet->dimy, cursheet->curx, cursheet->cury, cursheet->offx, cursheet->maxx, cursheet->offy, cursheet->maxy);
if (cursheet->dimx > cols()) cols(cursheet->dimx);
if (cursheet->dimy > rows()) rows(cursheet->dimy);
adjust_outside();
for (int x = 0; x < cursheet->dimx; x++) {
int w = columnwidth(cursheet, x, cursheet->curz)*10;
if (col_width(x) != w) col_width(x, w);
}
col_position(cursheet->offx);
row_position(cursheet->offy);
set_selection(cursheet->cury, cursheet->curx, cursheet->cury, cursheet->curx);
move_cursor(0,0);
updating = false;} {}
}
Function {update_sheet()} {return_type void
} {
code {int x1, x2, y1, y2;
if (updating) return;
updating = true;
get_selection(y1, x1, y2, x2);
if (x1 != x2 || y1 != y2) {
cursheet->mark1x = x1;
cursheet->mark1y = y1;
cursheet->mark2x = x2;
cursheet->mark2y = y2;
cursheet->mark1z = cursheet->mark2z = cursheet->curz;
cursheet->marking = 0;
}
moveto(cursheet, current_col, current_row, -1);
visible_cells(cursheet->offy, cursheet->maxy, cursheet->offx, cursheet->maxx);
cursheet->maxx -= cursheet->offx;
cursheet->maxy -= cursheet->offy;
if (is_interactive_resize()) {
for (int C = 0; C < cursheet->dimx; C++) {
int w = (col_width(C) + 5)/10;
if (w != columnwidth(cursheet, C, cursheet->curz)) setwidth(cursheet, C, cursheet->curz, w);
}
}
updating = false;
//printf("update_sheet: %ix%i@%i,%i; %i[%i], %i[%i] (%i,%i)-(%i,%i)\\n", cols(), rows(), cursheet->curx, cursheet->cury, cursheet->offx, cursheet->maxx, cursheet->offy, cursheet->maxy, x1, y1, x2, y2);} {}
}
Function {handle(int event)} {open return_type int
} {
code {if (event == FL_KEYDOWN) {
int ctrl = Fl::event_ctrl();
int alt = Fl::event_alt();
int shift = Fl::event_shift();
Key k = (Key)Fl::event_key();
switch ((unsigned int)k) {
case FL_Escape: k = K_INVALID; break;
case FL_BackSpace: k = K_BACKSPACE; break;
case FL_F+1: k = ctrl?K_ABOUT:K_HELP; break;
case FL_F+8: k = ctrl?K_RECALC:K_CLOCK; break;
case FL_F+9: k = ctrl?K_RECALC:K_CLOCK; break;
case FL_F+10: k = (Key)'/'; break;
case FL_Tab: if (shift) { k = K_CLOCK; break; }
case FL_Enter:
case FL_KP_Enter: k = alt?K_MENTER:K_ENTER; break;
case 'c': if (ctrl) { do_mark(cursheet, 2); cut = false; k = K_NONE; } break;
case 'v': k = ctrl?(cut?BLOCK_MOVE:BLOCK_COPY):(Key)'v'; break;
case 'x': if (ctrl) { do_mark(cursheet, 2); cut = true, k = K_NONE; } break;
case 'r': if (ctrl) k = K_RECALC; break;
case 'd': if (ctrl && shift && debug_level > 0) k = K_DUMPCELL; break;
case FL_Insert: if (ctrl) { do_mark(cursheet, 2); cut = false; } k = !shift?K_NONE:cut?BLOCK_MOVE:BLOCK_COPY; break;
case FL_Delete: if (shift) { do_mark(cursheet, 2); cut = true; } k = shift?K_NONE:BLOCK_CLEAR; break;
case FL_Home: k = ctrl?K_FIRSTL:shift?K_FSHEET:K_HOME; break;
case FL_End: k = ctrl?K_LASTL:shift?K_LSHEET:K_END; break;
case FL_Up: if (shift && !cursheet->marking) do_mark(cursheet, 1); k = ctrl?K_PPAGE:K_UP; break;
case FL_Down: if (shift && !cursheet->marking) do_mark(cursheet, 1); k = ctrl?K_NPAGE:K_DOWN; break;
case FL_Right: if (shift && !cursheet->marking) do_mark(cursheet, 1); k = ctrl?K_FPAGE:K_RIGHT; break;
case FL_Left: if (shift && !cursheet->marking) do_mark(cursheet, 1); k = ctrl?K_BPAGE:K_LEFT; break;
case FL_Page_Down: k = shift?K_NSHEET:ctrl?K_LASTL :K_NPAGE; break;
case FL_Page_Up: k = shift?K_PSHEET:ctrl?K_FIRSTL:K_PPAGE; break;
}
if (k > 0 && (ctrl || alt)) return 0;
// Quick and dirty upper-case fix, fails for international chars on keyboards...
if (shift && !alt && !ctrl && k >= 'a' && k <= 'z') k = (Key)(k - 'a' + 'A');
do_sheetcmd(cursheet, k, cursheet->moveonly);
do_callback(ACTION, 0, 0);
redraw();
} else if (event == FL_FOCUS) {
do_callback(REFRESH, 0, 0);
return 1;
} else if (event == FL_PUSH) {
int ex = Fl::event_x() - x(), ey = Fl::event_y() - y();
if (ex >= row_header_width() || ey >= col_header_height()) {
int rc = Fl_Table::handle(event);
do_callback(ACTION, 0, 0);
return rc;
}
if (ex < row_header_width()/2) relmoveto(cursheet, 0, 0, -1);
else relmoveto(cursheet, 0, 0, 1);
return 1;
} else if (event != FL_KEYUP) {
return Fl_Table::handle(event);
}
return 1;} {}
}
Function {adjust_outside()} {open protected return_type void
} {
code {int x1, x2, y1, y2;
if (!cols() || !rows()) {
cols(1);
rows(1);
}
visible_cells(y1, y2, x1, x2);
//printf("adj: (%i,%i)-(%i,%i) %ix%i\\n", x1, y1, x2, y2, cols(), rows());
if (x2+2 < cols() && cols() > cursheet->dimx) cols(x2+2 < cursheet->dimx?cursheet->dimx:x2+2);
else if (x2+1 == cols()) {
int xpos = col_scroll_position(cols());
int w = col_width(cols()-1);
x2 += (tow + hscrollbar->value() - xpos) / w + 2;
//printf(" : t: %i, w: %i, p: %i, r: %i\\n", tow, w, xpos, x2+1);
cols(x2+1);
}
if (y2+2 < rows() && rows() > cursheet->dimy) rows(y2+2 < cursheet->dimy?cursheet->dimy:y2+2);
else if (y2+1 == rows()) {
int ypos = row_scroll_position(rows());
int h = row_height(rows()-1);
y2 += (toh + vscrollbar->value() - ypos) / h + 2;
rows(y2+1);
}} {}
}
}
class MainWindow {open
} {
decl {static MainWindow *current;} {protected local
}
decl {int edit_rc;} {private local
}
Function {MainWindow(Sheet *sheet)} {open
} {
Fl_Window window {
label teapot
callback {if (Fl::event_key(FL_Escape)) table->take_focus();
else if (do_sheetcmd(table->sheet(), K_QUIT, 0) && doanyway(table->sheet(), _("Sheet modified, leave anyway?"))) {
line_label->deactivate();
window->hide();
}} open
protected xywh {866 342 800 600} type Double when 0 hide resizable
} {
Fl_Menu_Bar menu {
callback {Sheet *sheet = table->sheet();
Key action = (Key)(intptr_t)o->mvalue()->user_data();
if (do_sheetcmd(sheet, action, sheet->moveonly) && doanyway(sheet, _("Sheet modified, leave anyway?"))) {
window->hide();
return;
}
table->update_table();
table->redraw();} open
xywh {0 0 800 25}
class Fl_Sys_Menu_Bar
} {
Submenu {} {
label {&File}
xywh {25 25 67 24}
} {
MenuItem {} {
label {&Open...}
user_data K_LOADMENU
xywh {5 5 30 20} shortcut 0x4006f
}
MenuItem {} {
label {&Save}
user_data K_SAVE
xywh {0 0 30 20} shortcut 0x40073
}
MenuItem {} {
label {Save &As...}
user_data K_NAME
xywh {0 0 30 20} shortcut 0x50053 divider
}
MenuItem {} {
label {&Quit}
user_data K_QUIT
xywh {0 0 30 20} shortcut 0x40071
}
}
Submenu {} {
label {&Block}
xywh {25 25 67 24}
} {
MenuItem {} {
label {&Insert}
user_data BLOCK_INSERT
xywh {0 0 30 20} shortcut 0x90069
}
MenuItem {} {
label {&Delete}
user_data BLOCK_DELETE
xywh {0 0 30 20} shortcut 0x90064 divider
}
MenuItem {} {
label {&Move}
user_data BLOCK_MOVE
xywh {0 0 30 20} shortcut 0x9006d
}
MenuItem {} {
label {&Copy}
user_data BLOCK_COPY
xywh {0 0 36 21} shortcut 0x90063 divider
}
MenuItem {} {
label {&Fill}
user_data BLOCK_FILL
xywh {0 0 36 21} shortcut 0x90066
}
MenuItem {} {
label {C&lear}
user_data BLOCK_CLEAR
xywh {0 0 36 21} shortcut 0x9006c divider
}
MenuItem {} {
label {&Sort}
user_data BLOCK_SORT
xywh {0 0 36 21} shortcut 0x90073
}
MenuItem {} {
label {Mi&rror}
user_data BLOCK_MIRROR
xywh {0 0 36 21} shortcut 0x90072
}
}
Submenu {} {
label {&View}
xywh {0 0 70 21}
} {
MenuItem {} {
label {Column &Width...}
user_data K_COLWIDTH
xywh {0 0 36 21} shortcut 0x80077
}
MenuItem {} {
label {&Goto}
user_data K_GOTO
xywh {0 0 36 21} shortcut 0x40067
}
}
Submenu {} {
label {F&ormat} open
xywh {5 5 70 21}
} {
MenuItem {} {
label {L&abel...}
user_data ADJUST_LABEL
xywh {0 0 36 21} shortcut 0x80061 divider
}
MenuItem bold {
label {&Bold}
user_data ADJUST_BOLD
protected xywh {0 0 34 21} shortcut 0x80062
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem underline {
label {&Underline}
user_data ADJUST_UNDERLINE
protected xywh {0 0 34 21} shortcut 0x80075 divider
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem left {
label {&Left}
user_data ADJUST_LEFT
protected xywh {0 0 36 21} shortcut 0x8006c
code0 {o->flags |= FL_MENU_RADIO;}
}
MenuItem right {
label {&Right}
user_data ADJUST_RIGHT
protected xywh {0 0 36 21} shortcut 0x80072
code0 {o->flags |= FL_MENU_RADIO;}
}
MenuItem center {
label {&Center}
user_data ADJUST_CENTER
protected xywh {0 0 36 21} shortcut 0x80063 divider
code0 {o->flags |= FL_MENU_RADIO;}
}
MenuItem {} {
label {&Precision...}
user_data ADJUST_PRECISION
xywh {0 0 36 21} shortcut 0x80070 divider
}
MenuItem sci {
label {&Scientific}
user_data ADJUST_SCIENTIFIC
protected xywh {0 0 36 21} shortcut 0x80073
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem shadow {
label {Shadow&ed}
user_data ADJUST_SHADOW
protected xywh {0 0 36 21} shortcut 0x80065
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem transparent {
label {&Transparent}
user_data ADJUST_TRANSPARENT
protected xywh {0 0 36 21} shortcut 0x80074 divider
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem lock {
label {Lo&ck}
user_data ADJUST_LOCK
protected xywh {0 0 36 21} shortcut 0x80063
code0 {o->flags |= FL_MENU_TOGGLE;}
}
MenuItem ignore {
label {&Ignore}
user_data ADJUST_IGNORE
protected xywh {0 0 36 21} shortcut 0x80069
code0 {o->flags |= FL_MENU_TOGGLE;}
}
}
Submenu {} {
label {&Help} open
xywh {25 25 67 24}
} {
MenuItem {} {
label {&Manual}
user_data K_HELP
xywh {0 0 30 20} shortcut 0xffbe
}
MenuItem {} {
label {&About}
user_data K_ABOUT
xywh {0 0 30 20}
}
}
}
Fl_Group line_label {
label { Input:} open
protected xywh {0 25 800 25} box ROUND_UP_BOX align 20 deactivate
} {
Fl_Input line_input {
callback {bool enterkey = Fl::event_key(FL_Enter) || Fl::event_key(FL_KP_Enter);
if (Fl::focus() && (Fl::focus() != table || enterkey || Fl::event_key(FL_Escape))) {
if (enterkey) edit_rc = 0;
line_label->deactivate();
}}
protected xywh {75 27 723 21} box ROUND_DOWN_BOX labeltype NO_LABEL align 20 when 6 deactivate
}
}
Fl_Box table {
callback {Sheet *sheet = table->sheet();
table->update_sheet();
const char *label = getlabel(sheet,sheet->curx,sheet->cury,sheet->curz);
char moveonly=sheet->moveonly ? *_("V") : *_("E");
char buf[1024];
if (*label == 0) snprintf(buf, sizeof(buf), "%c @@(%d,%d,%d)=", moveonly, sheet->curx, sheet->cury, sheet->curz);
else snprintf(buf, sizeof(buf), "%c @@(%s)=", moveonly, label);
if (moveonly && table->callback_context() == TeapotTable::ACTION) {
char valbuf[1024] = "";
if (Fl::event_key() == 'p' || Fl::event_button1()) sprintf(valbuf, "(%i,%i,%i)", sheet->curx, sheet->cury, sheet->curz);
else if (Fl::event_key() == 'v') printvalue(valbuf,sizeof(valbuf),0,1,getscientific(sheet,sheet->curx,sheet->cury,sheet->curz),-1,sheet,sheet->curx,sheet->cury,sheet->curz);
else if (Fl::event_key(FL_Tab)) line_input->take_focus();
if (valbuf[0]) {
line_input->insert(valbuf);
line_input->take_focus();
}
}
char *err;
char val[1024];
if ((err = geterror(sheet, sheet->curx, sheet->cury, sheet->curz))) {
strncpy(val,err,sizeof(val));
free(err);
val[sizeof(val)-1] = 0;
} else {
print(val,sizeof(val),0,1,getscientific(sheet,sheet->curx,sheet->cury,sheet->curz),-1,getcont(sheet,sheet->curx,sheet->cury,sheet->curz,0));
if (getcont(sheet,sheet->curx,sheet->cury,sheet->curz,1)) {
snprintf(val+strlen(val),sizeof(val)-strlen(val)," -> ");
print(val+strlen(val),sizeof(val)-strlen(val),0,1,getscientific(sheet,sheet->curx,sheet->cury,sheet->curz),-1,getcont(sheet,sheet->curx,sheet->cury,sheet->curz,1));
}
}
line_edit(sheet, val, 0, buf, 0, 0);
int x = sheet->curx, y = sheet->cury, z = sheet->curz;
int adj = getadjust(sheet, x, y, z);
if (adj == LEFT) left->setonly();
else if (adj == RIGHT) right->setonly();
else if (adj == CENTER) center->setonly();
if (shadowed(sheet, x+1, y, z)) shadow->set();
else shadow->clear();
if (::transparent(sheet, x, y, z)) transparent->set();
else transparent->clear();
if (locked(sheet, x, y, z)) lock->set();
else lock->clear();
if (ignored(sheet, x, y, z)) ignore->set();
else ignore->clear();
if (isbold(sheet, x, y, z)) bold->set();
else bold->clear();
if (underlined(sheet, x, y, z)) underline->set();
else underline->clear();
if (getscientific(sheet, x, y, z)) sci->set();
else sci->clear();}
protected xywh {0 50 800 525} box DOWN_FRAME labeltype NO_LABEL resizable
code0 {table->sheet(sheet);}
class TeapotTable
}
Fl_Box status {
label {teapot ready.}
protected xywh {0 575 800 25} box GTK_ROUND_DOWN_BOX align 20
}
}
code {current = this;} {}
}
Function {line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *x, size_t *offx)} {open return_type int
} {
code {if (line_label->active()) {
if (x) line_msg(NULL, "Action not possible at this time.");
return -1;
}
line_label->copy_label(prompt);
int ww = 0, hh = 0;
line_label->measure_label(ww, hh);
line_input->resize(line_label->x()+ww+5, line_input->y(), line_label->w()-ww-7, line_input->h());
line_input->value(buf);
if (!x) return 0;
line_input->maximum_size(size);
line_input->position(*x, *x);
line_label->activate();
line_input->activate();
table->sheet()->moveonly = 1;
line_input->take_focus();
edit_rc = -1;
while (line_label->active()) Fl::wait();
memcpy(buf, line_input->value(), size);
line_input->deactivate();
table->sheet()->moveonly = 0;
table->take_focus();
return edit_rc;} {}
}
Function {line_msg(const char *prompt, const char *msg)} {return_type void
} {
code {char label[1024];
snprintf(label, sizeof(label), "%s%s%s", prompt?prompt:"", prompt?" ":"", msg);
status->copy_label(label);} {}
}
decl {friend void line_msg(const char*, const char*);} {private local
}
}
Function {line_file(const char *file, const char *pattern, const char *title, int create)} {open C return_type {const char *}
} {
code {static char buf[PATH_MAX];
Fl_Native_File_Chooser chooser;
chooser.title(title);
chooser.type(create?Fl_Native_File_Chooser::BROWSE_SAVE_FILE:Fl_Native_File_Chooser::BROWSE_FILE);
chooser.filter(pattern);
chooser.options((create?Fl_Native_File_Chooser::NEW_FOLDER:0)|Fl_Native_File_Chooser::SAVEAS_CONFIRM);
if (file) {
fl_filename_absolute(buf, sizeof(buf), file);
char *p = (char *)fl_filename_name(buf);
*p = 0;
chooser.directory(buf);
}
if (chooser.show()) return NULL;
strncpy(buf, chooser.filename(), sizeof(buf));
buf[sizeof(buf)-1] = 0;
return buf;} {}
}
Function {line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *x, size_t *offx)} {C return_type int
} {
code {if (sheet) return ((MainWindow*)((TeapotTable*)sheet->display)->parent()->user_data())->line_edit(sheet, buf, size, prompt, x, offx);
const char *val = fl_input("%s", buf, prompt);
if (val) {
strncpy(buf, val, size);
buf[size-1] = 0;
}
return !val;} {}
}
Function {line_ok(const char *prompt, int curx)} {C return_type int
} {
code {int rc = !!fl_choice("%s", "&No", NULL, "&Yes", prompt);
if (Fl::event_key(FL_Escape)) return -1;
return rc;} {}
}
Function {line_msg(const char *prompt, const char *msg)} {C return_type void
} {
code {MainWindow::current->line_msg(prompt, msg);} {}
}
Function {keypressed()} {open C return_type int
} {
code {while (Fl::wait(.01)) if (Fl::event_key(FL_Escape)) return 1;
return 0;} {}
}
Function {line_menu(const char *prompt, const MenuChoice *choice, int curx)} {C return_type int
} {
Fl_Window line_menu_menu {
label {Please Choose} open
xywh {706 58 250 245} type Double hide resizable modal
} {
Fl_Group {} {
label {Please Choose:} open
xywh {0 0 250 200} box ENGRAVED_BOX align 21
} {
Fl_Browser line_menu_browser {
callback {line_menu_menu->hide();}
xywh {5 25 240 170}
class Fl_Select_Browser
}
}
Fl_Button {} {
label Cancel
callback {line_menu_menu->hide();}
xywh {5 205 240 35}
}
}
code {line_menu_browser->clear();
while (choice->str) {
line_menu_browser->add(choice->str+1);
choice++;
}
line_menu_menu->show();
while (line_menu_menu->shown()) Fl::wait();
return line_menu_browser->value()-1;} {}
}
Function {redraw_sheet(Sheet *sheet)} {C return_type void
} {
code {TeapotTable *t = (TeapotTable*)sheet->display;
t->update_table();
t->redraw();} {}
}
Function {redraw_cell(Sheet *sheet, int x, int y, int z)} {C return_type void
} {
code {redraw_sheet(sheet);} {}
}
Function {display_init(Sheet *sheet, int always_redraw)} {open C return_type void
} {
code {Fl::get_system_colors();
\#ifdef ENABLE_HELP
Fl_File_Icon::load_system_icons();
\#endif
Fl::scheme("gtk+");
int ch = sheet->changed;
resize(sheet, 1, 1, 1);
sheet->changed = ch;
new MainWindow(sheet);} {}
}
Function {display_end()} {C return_type void
} {
code {} {}
}
Function {display_main(Sheet *cursheet)} {C return_type void
} {
code {((TeapotTable *)cursheet->display)->parent()->show();
Fl::run();} {}
}
Function {show_menu(Sheet *sheet)} {C return_type Key
} {
code {return K_NONE;} {}
}
decl {MainWindow *MainWindow::current;} {private global
}
declblock {\#ifdef ENABLE_HELP} {after {\#endif}
} {
decl {\#include <FL/Fl_Help_Dialog.H>} {private global
}
Function {show_text(const char *text)} {open C return_type void
} {
code {Fl_Help_Dialog *d = new Fl_Help_Dialog();
if (strchr(text, '<')) {
d->value(text);
} else {
d->load(text);
}
d->resize(d->x(), d->y(), d->w()*3/2, d->h()*3/2);
d->show();} {}
}
}
declblock {\#ifndef ENABLE_HELP} {after {\#endif}
} {
Function {show_text(const char *text)} {open C return_type void
} {
code {char *txt = striphtml(text);
fl_message("%s", txt);
free(txt);} {}
}
}
Function {find_helpfile(char *buf, int size, const char *argv0)} {open C return_type void
} {
code {fl_filename_absolute(buf, size, argv0);
char *p = (char *)fl_filename_name(buf);
strncpy(p, "../share/doc/teapot/html/index.html", buf+size-p);
buf[size-1] = 0;
// Check if help exists in default installed location, fallback value is valid for build directory
int test = open(buf, O_RDONLY);
if (test < 0) strncpy(p, "html/index.html", buf+size-p);
else close(test);
buf[size-1] = 0;
// Try the configure-time determined value
test = open(buf, O_RDONLY);
if (test < 0) strncpy(buf, HELPFILE, size);
else close(test);
buf[size-1] = 0;
// Fall back to a sane value for unixoid systems
test = open(buf, O_RDONLY);
if (test < 0) strncpy(buf, "/usr/share/doc/teapot/html/index.html", size);
else close(test);
buf[size-1] = 0;
} {}
}