mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
implement enter, leve cell callbacks
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@413 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
fba652b072
commit
349b53757f
@ -20,8 +20,9 @@ void xaccInitSingleCell (SingleCell *cell)
|
|||||||
cell->width = 0;
|
cell->width = 0;
|
||||||
cell->alignment = 0;
|
cell->alignment = 0;
|
||||||
cell->value = 0x0;
|
cell->value = 0x0;
|
||||||
|
cell->enter_cell = NULL;
|
||||||
cell->modify_verify = NULL;
|
cell->modify_verify = NULL;
|
||||||
cell->extdata = NULL;
|
cell->leave_cell = NULL;
|
||||||
cell->block = NULL;
|
cell->block = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,24 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* The modify-verify callback is called when a user
|
/*
|
||||||
|
* The enter_cell() callback is called when the user first
|
||||||
|
* makes a move to enter a cell. The current value of the
|
||||||
|
* cell is passed as the argument. If the callback wishes
|
||||||
|
* to change the value of the cell, it can return a non-null
|
||||||
|
* string. Alternately, to leave the value of the cell
|
||||||
|
* unchanged, it can return NULL. If a string is returned,
|
||||||
|
* the string must be as the result of a malloc.
|
||||||
|
*
|
||||||
|
* The leave_cell() callback is called when the user exits
|
||||||
|
* a cell. The current value of the cell is passed as the
|
||||||
|
* argument. If the callback wishes to change the value of
|
||||||
|
* the cell, it can return a non-null string. Alternately,
|
||||||
|
* to leave the value of the cell unchanged, it can return
|
||||||
|
* NULL. If a string is returned, the string must be as the
|
||||||
|
* result of a malloc.
|
||||||
|
*
|
||||||
|
* The modify-verify callback is called when a user
|
||||||
* makes a change to a cell.
|
* makes a change to a cell.
|
||||||
* The three arguments passed in are :
|
* The three arguments passed in are :
|
||||||
* "old", the string prior to user's attempted modification,
|
* "old", the string prior to user's attempted modification,
|
||||||
@ -46,13 +63,13 @@ typedef struct _SingleCell {
|
|||||||
/* private data */
|
/* private data */
|
||||||
char * value; /* current value */
|
char * value; /* current value */
|
||||||
|
|
||||||
|
const char * (*enter_cell) (const char * current);
|
||||||
const char * (*modify_verify) (const char *old,
|
const char * (*modify_verify) (const char *old,
|
||||||
const char *add,
|
const char *add,
|
||||||
const char *new);
|
const char *new);
|
||||||
|
const char * (*leave_cell) (const char * current);
|
||||||
|
|
||||||
struct _CellBlock *block; /* back-pointer to parent container */
|
struct _CellBlock *block; /* back-pointer to parent container */
|
||||||
void * extdata; /* generic extension mechanism */
|
|
||||||
} SingleCell;
|
} SingleCell;
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,11 @@
|
|||||||
#include "cell.h"
|
#include "cell.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
|
|
||||||
|
static void enterCB (Widget mw, XtPointer cd, XtPointer cb);
|
||||||
|
static void leaveCB (Widget mw, XtPointer cd, XtPointer cb);
|
||||||
|
static void modifyCB (Widget mw, XtPointer cd, XtPointer cb);
|
||||||
|
static void traverseCB (Widget mw, XtPointer cd, XtPointer cb);
|
||||||
|
|
||||||
Table *
|
Table *
|
||||||
xaccMallocTable (int tile_rows, int tile_cols)
|
xaccMallocTable (int tile_rows, int tile_cols)
|
||||||
{
|
{
|
||||||
@ -123,56 +128,31 @@ xaccRefreshHeader (Table *table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ==================================================== */
|
/* ==================================================== */
|
||||||
|
/* this routine calls the individual cell callbacks */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
enterCB (Widget mw, XtPointer cd, XtPointer cb)
|
cellCB (Widget mw, XtPointer cd, XtPointer cb)
|
||||||
{
|
{
|
||||||
Table *table;
|
Table *table;
|
||||||
XbaeMatrixDefaultActionCallbackStruct *cbs;
|
XbaeMatrixDefaultActionCallbackStruct *cbs;
|
||||||
int row, col;
|
int row, col;
|
||||||
|
|
||||||
table = (Table *) cd;
|
|
||||||
cbs = (XbaeMatrixDefaultActionCallbackStruct *)cb;
|
|
||||||
|
|
||||||
row = cbs->row;
|
|
||||||
col = cbs->column;
|
|
||||||
|
|
||||||
if (XbaeEnterCellReason != cbs->reason) return;
|
|
||||||
|
|
||||||
printf ("enter %d %d \n", row, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==================================================== */
|
|
||||||
/* this routine calls the individual cell callbacks */
|
|
||||||
|
|
||||||
static void
|
|
||||||
modifyCB (Widget mw, XtPointer cd, XtPointer cb)
|
|
||||||
{
|
|
||||||
Table *table;
|
|
||||||
XbaeMatrixModifyVerifyCallbackStruct *cbs;
|
|
||||||
int row, col;
|
|
||||||
int rel_row, rel_col;
|
int rel_row, rel_col;
|
||||||
CellBlock *arr;
|
CellBlock *arr;
|
||||||
|
int invalid = 0;
|
||||||
|
|
||||||
table = (Table *) cd;
|
table = (Table *) cd;
|
||||||
cbs = (XbaeMatrixModifyVerifyCallbackStruct *) cb;
|
cbs = (XbaeMatrixDefaultActionCallbackStruct *) cb;
|
||||||
|
|
||||||
row = cbs->row;
|
row = cbs->row;
|
||||||
col = cbs->column;
|
col = cbs->column;
|
||||||
|
|
||||||
if (XbaeModifyVerifyReason != cbs->reason) return;
|
|
||||||
|
|
||||||
printf ("modify %d %d %s \n", row, col, cbs->verify->text->ptr);
|
|
||||||
|
|
||||||
/* reject edits by default, unless the cell handler allows them */
|
|
||||||
cbs->verify->doit = False;
|
|
||||||
|
|
||||||
/* can't edit outside of the physical space */
|
/* can't edit outside of the physical space */
|
||||||
if ((0 > row) || (0 > col)) return;
|
invalid = (0 > row) || (0 > col) ;
|
||||||
if ((row >= table->num_phys_rows) || (col >= table->num_phys_cols)) return;
|
invalid = invalid || (row >= table->num_phys_rows);
|
||||||
|
invalid = invalid || (col >= table->num_phys_cols);
|
||||||
|
|
||||||
/* header rows cannot be modified */
|
/* header rows cannot be modified */
|
||||||
if (row < table->num_header_rows) return;
|
invalid = invalid || (row < table->num_header_rows);
|
||||||
|
|
||||||
/* compute the cell location */
|
/* compute the cell location */
|
||||||
rel_row = row;
|
rel_row = row;
|
||||||
@ -186,86 +166,280 @@ modifyCB (Widget mw, XtPointer cd, XtPointer cb)
|
|||||||
if (arr) {
|
if (arr) {
|
||||||
rel_row %= (arr->numRows);
|
rel_row %= (arr->numRows);
|
||||||
rel_col %= (arr->numCols);
|
rel_col %= (arr->numCols);
|
||||||
if (arr->cells[rel_row][rel_col]) {
|
if (! (arr->cells[rel_row][rel_col])) invalid = TRUE;
|
||||||
const char * (*mv) (const char *, const char *, const char *);
|
} else {
|
||||||
mv = arr->cells[rel_row][rel_col]->modify_verify;
|
invalid = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* OK, if there is a callback for this cell, call it */
|
/* oops the callback failed for some reason ...
|
||||||
if (mv) {
|
* reject the enter/edit/leave and return */
|
||||||
const char *old, *change;
|
if (invalid) {
|
||||||
char *new;
|
switch (cbs->reason) {
|
||||||
const char *retval;
|
case XbaeEnterCellReason: {
|
||||||
int len;
|
XbaeMatrixEnterCellCallbackStruct *ecbs;
|
||||||
|
ecbs = (XbaeMatrixEnterCellCallbackStruct *) cbs;
|
||||||
old = cbs->prev_text;
|
ecbs->doit = False;
|
||||||
change = cbs->verify->text->ptr;
|
ecbs->map = False;
|
||||||
|
break;
|
||||||
/* but first, compute the new string */
|
|
||||||
len = 1;
|
|
||||||
if (old) len += strlen (old);
|
|
||||||
if (change) len += strlen (change);
|
|
||||||
new = (char *) malloc (len);
|
|
||||||
|
|
||||||
/* text may be inserted, or deleted, or replaced ... */
|
|
||||||
new[0] = 0;
|
|
||||||
strncat (new, old, cbs->verify->startPos);
|
|
||||||
if (change) strcat (new, change);
|
|
||||||
strcat (new, &old[(cbs->verify->endPos)]);
|
|
||||||
|
|
||||||
retval = (*mv) (old, change, new);
|
|
||||||
|
|
||||||
/* if the callback returned a non-null value, allow the edit */
|
|
||||||
if (retval) {
|
|
||||||
|
|
||||||
/* update data. bounds check done earlier */
|
|
||||||
free (table->entries[row][col]);
|
|
||||||
table->entries[row][col] = (char *) retval;
|
|
||||||
|
|
||||||
/* if the callback modified the display string,
|
|
||||||
* update the display cell as well */
|
|
||||||
if (retval != new) {
|
|
||||||
XbaeMatrixSetCell (mw, row, col, (char *) retval);
|
|
||||||
XbaeMatrixRefreshCell (mw, row, col);
|
|
||||||
XbaeMatrixSetCursorPosition (mw, (cbs->verify->endPos) +1);
|
|
||||||
|
|
||||||
/* the default update has already been overridden,
|
|
||||||
* so don't allow Xbae to update */
|
|
||||||
cbs->verify->doit = False;
|
|
||||||
|
|
||||||
/* avoid wasting memory */
|
|
||||||
free (new);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* the proposed edit was accepted! */
|
|
||||||
cbs->verify->doit = True;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* avoid wasting memory */
|
|
||||||
free(new);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case XbaeModifyVerifyReason: {
|
||||||
|
XbaeMatrixModifyVerifyCallbackStruct *mvcbs;
|
||||||
|
mvcbs = (XbaeMatrixModifyVerifyCallbackStruct *) cbs;
|
||||||
|
mvcbs->verify->doit = False;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case XbaeTraverseCellReason: {
|
||||||
|
XbaeMatrixTraverseCellCallbackStruct *tcbs;
|
||||||
|
tcbs = (XbaeMatrixTraverseCellCallbackStruct *) cbs;
|
||||||
|
tcbs->next_row = 0;
|
||||||
|
tcbs->next_column = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case XbaeLeaveCellReason: {
|
||||||
|
XbaeMatrixLeaveCellCallbackStruct *lcbs;
|
||||||
|
lcbs = (XbaeMatrixLeaveCellCallbackStruct *) cbs;
|
||||||
|
lcbs->doit = False;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we got to here, then there is a cell handler for
|
||||||
|
* this cell. Dispatch for processing. */
|
||||||
|
switch (cbs->reason) {
|
||||||
|
case XbaeEnterCellReason: {
|
||||||
|
enterCB (mw, cd, cb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case XbaeModifyVerifyReason: {
|
||||||
|
modifyCB (mw, cd, cb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case XbaeLeaveCellReason: {
|
||||||
|
leaveCB (mw, cd, cb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case XbaeTraverseCellReason: {
|
||||||
|
traverseCB (mw, cd, cb);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ==================================================== */
|
||||||
|
/* this callback assumes that basic error checking has already
|
||||||
|
* been performed. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
enterCB (Widget mw, XtPointer cd, XtPointer cb)
|
||||||
|
{
|
||||||
|
Table *table;
|
||||||
|
CellBlock *arr;
|
||||||
|
XbaeMatrixEnterCellCallbackStruct *cbs;
|
||||||
|
int row, col;
|
||||||
|
int rel_row, rel_col;
|
||||||
|
const char * (*enter) (const char *);
|
||||||
|
|
||||||
|
table = (Table *) cd;
|
||||||
|
arr = table->cursor;
|
||||||
|
cbs = (XbaeMatrixEnterCellCallbackStruct *) cb;
|
||||||
|
|
||||||
|
/* compute the cell location */
|
||||||
|
row = cbs->row;
|
||||||
|
col = cbs->column;
|
||||||
|
rel_row = row - table->num_header_rows;
|
||||||
|
rel_col = col;
|
||||||
|
rel_row %= (arr->numRows);
|
||||||
|
rel_col %= (arr->numCols);
|
||||||
|
|
||||||
|
printf ("enter %d %d \n", row, col);
|
||||||
|
|
||||||
|
/* since we are here, there must be a cell handler.
|
||||||
|
* therefore, we accept entry into the cell by default,
|
||||||
|
*/
|
||||||
|
cbs->doit = True;
|
||||||
|
cbs->map = True;
|
||||||
|
|
||||||
|
/* OK, if there is a callback for this cell, call it */
|
||||||
|
enter = arr->cells[rel_row][rel_col]->enter_cell;
|
||||||
|
if (enter) {
|
||||||
|
const char *val, *retval;
|
||||||
|
|
||||||
|
val = table->entries[row][col];
|
||||||
|
retval = enter (val);
|
||||||
|
if (val != retval) {
|
||||||
|
if (table->entries[row][col]) free (table->entries[row][col]);
|
||||||
|
table->entries[row][col] = (char *) retval;
|
||||||
|
XbaeMatrixSetCell (mw, row, col, (char *) retval);
|
||||||
|
XbaeMatrixRefreshCell (mw, row, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================== */
|
||||||
|
/* this routine calls the individual cell callbacks */
|
||||||
|
|
||||||
|
static void
|
||||||
|
modifyCB (Widget mw, XtPointer cd, XtPointer cb)
|
||||||
|
{
|
||||||
|
Table *table;
|
||||||
|
CellBlock *arr;
|
||||||
|
XbaeMatrixModifyVerifyCallbackStruct *cbs;
|
||||||
|
int row, col;
|
||||||
|
int rel_row, rel_col;
|
||||||
|
const char * (*mv) (const char *, const char *, const char *);
|
||||||
|
const char *oldval, *change;
|
||||||
|
char *newval;
|
||||||
|
const char *retval;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
table = (Table *) cd;
|
||||||
|
arr = table->cursor;
|
||||||
|
cbs = (XbaeMatrixModifyVerifyCallbackStruct *) cb;
|
||||||
|
|
||||||
|
/* compute the cell location */
|
||||||
|
row = cbs->row;
|
||||||
|
col = cbs->column;
|
||||||
|
rel_row = row;
|
||||||
|
rel_col = col;
|
||||||
|
rel_row -= table->num_header_rows;
|
||||||
|
rel_row %= (arr->numRows);
|
||||||
|
rel_col %= (arr->numCols);
|
||||||
|
|
||||||
|
/* accept edits by default, unless the cell handler rejects them */
|
||||||
|
cbs->verify->doit = True;
|
||||||
|
|
||||||
|
oldval = cbs->prev_text;
|
||||||
|
change = cbs->verify->text->ptr;
|
||||||
|
|
||||||
|
/* first, compute the newval string */
|
||||||
|
len = 1;
|
||||||
|
if (oldval) len += strlen (oldval);
|
||||||
|
if (change) len += strlen (change);
|
||||||
|
newval = (char *) malloc (len);
|
||||||
|
|
||||||
|
/* text may be inserted, or deleted, or replaced ... */
|
||||||
|
newval[0] = 0;
|
||||||
|
strncat (newval, oldval, cbs->verify->startPos);
|
||||||
|
if (change) strcat (newval, change);
|
||||||
|
strcat (newval, &oldval[(cbs->verify->endPos)]);
|
||||||
|
|
||||||
|
/* OK, if there is a callback for this cell, call it */
|
||||||
|
mv = arr->cells[rel_row][rel_col]->modify_verify;
|
||||||
|
if (mv) {
|
||||||
|
retval = (*mv) (oldval, change, newval);
|
||||||
|
|
||||||
|
/* if the callback returned a non-null value, allow the edit */
|
||||||
|
if (retval) {
|
||||||
|
|
||||||
|
/* update data. bounds check done earlier */
|
||||||
|
free (table->entries[row][col]);
|
||||||
|
table->entries[row][col] = (char *) retval;
|
||||||
|
|
||||||
|
/* if the callback modified the display string,
|
||||||
|
* update the display cell as well */
|
||||||
|
if (retval != newval) {
|
||||||
|
XbaeMatrixSetCell (mw, row, col, (char *) retval);
|
||||||
|
XbaeMatrixRefreshCell (mw, row, col);
|
||||||
|
XbaeMatrixSetCursorPosition (mw, (cbs->verify->endPos) +1);
|
||||||
|
|
||||||
|
/* the default update has already been overridden,
|
||||||
|
* so don't allow Xbae to update */
|
||||||
|
cbs->verify->doit = False;
|
||||||
|
|
||||||
|
/* avoid wasting memory */
|
||||||
|
free (newval);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* NULL return value means the edit was rejected */
|
||||||
|
cbs->verify->doit = False;
|
||||||
|
|
||||||
|
/* avoid wasting memory */
|
||||||
|
free(newval);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* update data. bounds check done earlier */
|
||||||
|
free (table->entries[row][col]);
|
||||||
|
table->entries[row][col] = strdup (newval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ==================================================== */
|
||||||
|
|
||||||
|
static void
|
||||||
|
leaveCB (Widget mw, XtPointer cd, XtPointer cb)
|
||||||
|
{
|
||||||
|
Table *table;
|
||||||
|
CellBlock *arr;
|
||||||
|
XbaeMatrixLeaveCellCallbackStruct *cbs;
|
||||||
|
int row, col;
|
||||||
|
int rel_row, rel_col;
|
||||||
|
const char * (*leave) (const char *);
|
||||||
|
|
||||||
|
table = (Table *) cd;
|
||||||
|
arr = table->cursor;
|
||||||
|
cbs = (XbaeMatrixLeaveCellCallbackStruct *) cb;
|
||||||
|
|
||||||
|
/* compute the cell location */
|
||||||
|
row = cbs->row;
|
||||||
|
col = cbs->column;
|
||||||
|
rel_row = row - table->num_header_rows;
|
||||||
|
rel_col = col;
|
||||||
|
rel_row %= (arr->numRows);
|
||||||
|
rel_col %= (arr->numCols);
|
||||||
|
|
||||||
|
printf ("leave %d %d \n", row, col);
|
||||||
|
|
||||||
|
/* by default, accept whateve the final roposed edit is */
|
||||||
|
cbs->doit = True;
|
||||||
|
|
||||||
|
/* OK, if there is a callback for this cell, call it */
|
||||||
|
leave = arr->cells[rel_row][rel_col]->leave_cell;
|
||||||
|
if (leave) {
|
||||||
|
const char *val, *retval;
|
||||||
|
|
||||||
|
val = cbs->value;
|
||||||
|
retval = leave (val);
|
||||||
|
if (val != retval) {
|
||||||
|
if (table->entries[row][col]) free (table->entries[row][col]);
|
||||||
|
table->entries[row][col] = (char *) retval;
|
||||||
|
cbs->value = strdup (retval);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (table->entries[row][col]) free (table->entries[row][col]);
|
||||||
|
table->entries[row][col] = strdup (cbs->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ==================================================== */
|
/* ==================================================== */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
traverseCB (Widget mw, XtPointer cd, XtPointer cb)
|
traverseCB (Widget mw, XtPointer cd, XtPointer cb)
|
||||||
{
|
{
|
||||||
Table *table;
|
Table *table;
|
||||||
XbaeMatrixDefaultActionCallbackStruct *cbs;
|
CellBlock *arr;
|
||||||
|
XbaeMatrixTraverseCellCallbackStruct *cbs;
|
||||||
int row, col;
|
int row, col;
|
||||||
|
int rel_row, rel_col;
|
||||||
|
|
||||||
table = (Table *) cd;
|
table = (Table *) cd;
|
||||||
cbs = (XbaeMatrixDefaultActionCallbackStruct *)cb;
|
arr = table->cursor;
|
||||||
|
cbs = (XbaeMatrixTraverseCellCallbackStruct *) cb;
|
||||||
|
|
||||||
|
/* compute the cell location */
|
||||||
row = cbs->row;
|
row = cbs->row;
|
||||||
col = cbs->column;
|
col = cbs->column;
|
||||||
|
rel_row = row - table->num_header_rows;
|
||||||
if (XbaeTraverseCellReason != cbs->reason) return;
|
rel_col = col;
|
||||||
|
rel_row %= (arr->numRows);
|
||||||
|
rel_col %= (arr->numCols);
|
||||||
|
|
||||||
printf ("traverse %d %d \n", row, col);
|
printf ("traverse %d %d \n", row, col);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -319,9 +493,10 @@ xaccCreateTable (Table *table, Widget parent, char * name)
|
|||||||
|
|
||||||
XtManageChild (reg);
|
XtManageChild (reg);
|
||||||
|
|
||||||
XtAddCallback (reg, XmNenterCellCallback, enterCB, (XtPointer)table);
|
XtAddCallback (reg, XmNenterCellCallback, cellCB, (XtPointer)table);
|
||||||
XtAddCallback (reg, XmNmodifyVerifyCallback, modifyCB, (XtPointer)table);
|
XtAddCallback (reg, XmNleaveCellCallback, cellCB, (XtPointer)table);
|
||||||
XtAddCallback (reg, XmNtraverseCellCallback, traverseCB, (XtPointer)table);
|
XtAddCallback (reg, XmNmodifyVerifyCallback, cellCB, (XtPointer)table);
|
||||||
|
XtAddCallback (reg, XmNtraverseCellCallback, cellCB, (XtPointer)table);
|
||||||
|
|
||||||
table->reg = reg;
|
table->reg = reg;
|
||||||
return (reg);
|
return (reg);
|
||||||
|
Loading…
Reference in New Issue
Block a user