EditTable Widget WebFAQ - Q7
/***
***
*** Example of an EditTable widget with pointer type data and a user-
*** formatted display.
***
*** The program uses the XintEditTableDefineColumnFormat and
*** XintEditTableFillColumnData functions.
***
******************************************************************************/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/MessageB.h>
#include <Xm/PushBG.h>
#include <Xm/Separator.h>
#include <Xm/RowColumn.h>
#include <Xint/Scroll.h>
#include <Xint/EditTable.h>
static String control_names[] = { "Help", "Exit" };
/* funtion forwarding */
static Widget CreateTargetWidgets();
static Widget CreateControls();
static void ControlCallback();
#define IMPORT_LIST 1
#define CHECK_1 2
#define COST_LIST 3
/* global variables */
Widget Toplevel; /* container for the user interface */
Arg arg[64];
static String column_annotations[] = {
"Date\n(ptr data)",
"Check #\n(integer)",
"Imports\n(user-format)",
};
typedef struct _ActivityRec {
int year;
int month;
int day;
} ActivityRec, *ActivityPtr;
static ActivityRec import_list[] = {
{ 1993, 1, 4 },
{ 1993, 2, 1 },
{ 1993, 3, 7 },
{ 1993, 4, 5 },
{ 1993, 5, 1 },
{ 1993, 6, 3 },
{ 1993, 7, 7 },
{ 1993, 8, 2 },
{ 1993, 9, 6 },
{ 1993, 10, 8 },
{ 1993, 11, 2 },
{ 1993, 12, 1 }
};
static int check_1[] = {
1452,
1475,
1494,
1750,
1802,
2803,
1969,
1998,
2252,
2302,
2390,
2452
};
static double cost_list[] = {
1452345.83,
1472897.47,
1492341.98,
1750351.35,
1802339.89,
1802462.52,
1969546.98,
1958845.46,
2252247.84,
2302840.73,
2390743.28,
2452345.15
};
/* translations */
static char selection_translations[] =
"Shift <Key>osfLeft: EditTableEnterCell(Left)\n\
Shift <Key>osfRight: EditTableEnterCell(Right)\n\
Shift <Key>osfUp: EditTableEnterCell(Up)\n\
Shift <Key>osfDown: EditTableEnterCell(Down)\n\
Shift <Btn1Down>: EditTableStartSelect(multiple)\n\
Button1<Motion>: EditTableExtendSelect()\n\
Shift <Btn2Down>: EditTableClearSelection()\n\
Shift <Btn3Down>: EditTableClearAllSelections()\n\
Ctrl <Btn1Down>: EditTableExtendSelect()";
static char annotation_translations[] =
"~Ctrl ~Shift ~Meta ~Alt <Btn1Down>: AnnotationStartSelect()\n\
Shift <Btn1Down>: AnnotationStartSelect(multiple)\n\
Button1<Motion>: AnnotationExtendSelect()\n\
Ctrl <Btn1Down>: AnnotationExtendSelect()\n\
<Btn1Up>: AnnotationEndSelect()\n\
Shift <Btn2Down>: EditTableClearSelection()\n\
Shift <Btn3Down>: EditTableClearAllSelections()";
main(argc, argv)
int argc;
char *argv[];
{
XtAppContext app_context;
Widget container, control_panel, target, sep;
int n;
n = 0;
XtSetArg(arg[n], XmNallowShellResize, True); n++;
Toplevel = XtAppInitialize(&app_context, "INT Example", NULL, 0,
&argc, argv, NULL, arg, n);
/* Create form to contain all other widgets */
n = 0;
container = XtCreateManagedWidget("container", xmFormWidgetClass,
Toplevel, arg, n);
/* Target Widgets */
n = 0;
/* constraint resources */
XtSetArg(arg[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
target = CreateTargetWidgets(container, arg, n);
/* Separator */
n = 0;
/* constraint resources */
XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
sep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, container, arg, n);
/* Controls */
n = 0;
/* constraint resources */
XtSetArg(arg[n], XmNorientation, XmHORIZONTAL); n++;
XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(arg[n], XmNbottomAttachment, XmATTACH_FORM); n++;
control_panel = CreateControls(container, arg, n);
/* fine tuning on layout */
XtVaSetValues(sep, XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, control_panel,
NULL);
XtVaSetValues(target, XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, sep,
NULL);
XtRealizeWidget(Toplevel);
XtAppMainLoop(app_context);
}
/*ARGSUSED*/
static void
SetCellDisplay(widget, unused, cb)
Widget widget;
XtPointer unused;
XintEditTableFormatCellCallbackStruct *cb;
{
static char buffer[64]; /* You can define a static buffer and reuse it. */
ActivityPtr activity;
double value;
int val;
Boolean negative;
switch (cb->column) {
case IMPORT_LIST:
if (cb->cell_value.pointer_value != XintUNDEFINED_POINTER) {
activity = (ActivityPtr) cb->cell_value.pointer_value;
cb->display_string = buffer;
sprintf(cb->display_string, "%02d/%02d/%04d",
activity->month, activity->day, activity->year);
}
break;
case COST_LIST:
if (cb->cell_value.double_value == XintUNDEFINED_DOUBLE) return;
/* You can also allocate the buffer for returning the string */
cb->display_string = XtMalloc(64 * sizeof(char));
/* And tell the EditTable to free the string after using it */
cb->to_be_freed = True;
value = (double) cb->cell_value.double_value;
negative = value < 0.0;
value = fabs(value);
val = (int) floor(value);
if (value >= 1000000.0) {
if (negative) {
sprintf(cb->display_string, "$(%d,%03d,%03d.%02d)", val / 1000000,
(val % 1000000) / 1000, val % 1000, (int) ((value - val) * 100));
} else {
sprintf(cb->display_string, "$%d,%03d,%03d.%02d", val / 1000000,
(val % 1000000) / 1000, val % 1000, (int) ((value - val) * 100));
}
} else if (value >= 1000.0) {
if (negative) {
sprintf(cb->display_string, "$(%d,%03d.%02d)", val / 1000,
val % 1000, (int) ((value - val) * 100));
} else {
sprintf(cb->display_string, "$%d,%03d.%02d", val / 1000,
val % 1000, (int) ((value - val) * 100));
}
} else {
if (negative) {
sprintf(cb->display_string, "$(%d.%02d)", val,
(int) ((value - val) * 100));
} else {
sprintf(cb->display_string, "$%d.%02d", val,
(int) ((value - val) * 100));
}
}
break;
default:;
}
}
static Boolean
CheckDays(month, day)
int month;
int day;
{
switch (month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
if (day < 1 || day > 31) return False;
break;
case 2:
/* check roughly. doesn't consider Feb of 29 days */
if (day < 1 || day > 28) return False;
break;
case 4: case 6: case 9: case 11:
if (day < 1 || day > 30) return False;
}
return True;
}
/*ARGSUSED*/
static void
ValidateValue(widget, unused, cb)
Widget widget;
XtPointer unused;
XintEditTableValidateValueCallbackStruct *cb;
{
ActivityPtr activity;
String value;
int i, j, k;
Boolean year_read, month_read, day_read;
/*
Here only do simple parsing on the member 'cb->new_value_string'.
More complicate parsing scheme may be needed depending on the
application.
*/
switch (cb->column) {
case IMPORT_LIST:
activity = (ActivityPtr) cb->cell_value.pointer_value;
i = 0;
year_read = month_read = day_read = False;
while (cb->new_value_string[i] != '\0') {
if (isdigit(cb->new_value_string[i])) {
if (!month_read) {
sscanf(&cb->new_value_string[i], "%d", &k);
if (k < 1 || k > 12) break;
activity->month = k;
month_read = True;
} else if (!day_read) {
sscanf(&cb->new_value_string[i], "%d", &k);
if (!CheckDays(activity->month, k)) break;
activity->day = k;
day_read = True;
} else if (!year_read) {
sscanf(&cb->new_value_string[i], "%d", &k);
if (k < 0) break;
activity->year = k;
year_read = True;
}
while (isdigit(cb->new_value_string[i])) i++;
} else {
i++;
}
}
if (!(day_read && month_read && year_read)) {
cb->doit = False;
}
break;
case COST_LIST:
break;
default:;
}
}
static Widget
CreateTargetWidgets(parent, arg, n)
Widget parent;
ArgList arg;
int n;
{
Widget scroll, table;
int j, ncols, nrows;
XtPointer *ptr_list;
double *profit_list;
XtTranslations translations;
extern int XintLoadColor();
XtSetArg(arg[n], XmNhorizontalAutoSized, True); n++;
XtSetArg(arg[n], XmNverticalAutoSized, True); n++;
scroll = XtCreateManagedWidget("scroll", xintScrollWidgetClass,
parent, arg, n);
translations = XtParseTranslationTable(annotation_translations);
table = XtVaCreateManagedWidget("table", xintEditTableWidgetClass, scroll,
XmNtitleString, "XintEditTable Example\nPointer Type Data\n\
and\nUser-Formatted Display",
XmNtitleFont, "*times-bold-r-*-24-*",
XmNtitleShadowType, XintSHADOW_OUT,
XmNtitleBackground, XintLoadColor(XtDisplay(parent), "cyan"),
XmNgridLineStyle, XintGRID_LINE_SHADOW_OUT,
XmNcolumnAnnotationTranslations, translations,
XmNrowAnnotationTranslations, translations,
XmNautoMarginAdjust, XintADJUST_ALL,
XmNgridLineOrientation, XintGRID_LINE_COLUMNWISE,
XmNdefaultColumnAlignment, XintALIGNMENT_CENTER_MIDDLE,
XmNautomaticColumnAnnotation, False,
XmNnumberOfColumns, 3,
XmNnumberOfRows, 12,
XmNcolumnAnnotationData, column_annotations,
XmNdefaultColumnDataType, XintTYPE_INTEGER,
XmNdefaultColumnDataFormat, "%d",
NULL);
XtOverrideTranslations(table, XtParseTranslationTable(selection_translations));
XtAddCallback(table, XmNformatCellCallback,
(XtCallbackProc) SetCellDisplay, NULL);
XtAddCallback(table, XmNvalidateValueCallback,
(XtCallbackProc) ValidateValue, NULL);
XtVaGetValues(table, XmNnumberOfRows, &nrows,
XmNnumberOfColumns, &ncols, NULL);
/* set pointer data */
ptr_list = (XtPointer *) XtMalloc(nrows * sizeof(XtPointer));
XintEditTableDefineColumnFormat(table, IMPORT_LIST,
XintCOLUMN_DEFAULT,
XintCOLUMN_DEFAULT,
10,
XintTYPE_POINTER,
(String) XintCOLUMN_DEFAULT);
for (j = 0; j < nrows; j++) ptr_list[j] = (XtPointer) &(import_list[j]);
XintEditTableFillColumnData(table, IMPORT_LIST, (XtPointer) ptr_list);
XtFree((char *)ptr_list);
/* set integer data */
XintEditTableDefineColumnFormat(table, CHECK_1,
XintCOLUMN_DEFAULT,
XintCOLUMN_DEFAULT,
5,
XintCOLUMN_DEFAULT,
(String) XintCOLUMN_DEFAULT);
/* for simplicity, here use static data. */
XintEditTableFillColumnData(table, CHECK_1, (XtPointer) check_1);
/* set double-precision float data */
XintEditTableDefineColumnFormat(table, COST_LIST,
XintCOLUMN_DEFAULT,
XintALIGNMENT_END_MIDDLE,
14,
XintTYPE_DOUBLE,
NULL);
/* for simplicity, here use static data. */
XintEditTableFillColumnData(table, COST_LIST, (XtPointer) cost_list);
return scroll;
}
static Widget
CreateControls(parent, arg, n)
Widget parent;
ArgList arg;
int n;
{
XmString name;
Widget panel, button;
int i;
panel = XtCreateManagedWidget("control_panel", xmRowColumnWidgetClass,
parent, arg, n);
/* create control pushbuttons */
n = 0;
XtSetArg(arg[n], XmNpushButtonEnabled, True); n++;
XtSetArg(arg[n], XmNmarginWidth, 4); n++;
XtSetArg(arg[n], XmNmarginHeight, 4); n++;
for (i = 0; i < XtNumber(control_names); i++) {
name = XmStringCreateLtoR(control_names[i], XmSTRING_DEFAULT_CHARSET);
XtSetArg(arg[n], XmNlabelString, name);
button = XtCreateManagedWidget("control_button", xmPushButtonGadgetClass,
panel, arg, n + 1);
XtAddCallback(button, XmNactivateCallback, (XtCallbackProc) ControlCallback,
(XtPointer)i);
XmStringFree(name);
}
return panel;
}
static void
Help()
{
static Widget message_box = NULL;
if (message_box == NULL) {
static char help_text[] =
"Descriptions:\n\
\n\
Pointer Data:\n\
Columns of 'Date' contain pointers pointing\n\
to application-defined structures as follow:\n\
\n\
typedef struct _ActivityRec {\n\
int year;\n\
int month;\n\
int day;\n\
} ActivityRec, *ActivityPtr;\n\
\n\
The application can convert such composite\n\
data, through the XmNformatCellCallback rou-\n\
tine, into any kind display format.\n\
\n\
User-Formatted Display:\n\
Column of 'Imports' contain just double-precision \n\
floating point data. Again, the application \n\
has the choice to convert the display into any \n\
kind of desired format (such as dollar-sign prefix,\n\
comma separator) through the XmNformatCell-\n\
Callback routine.\n\
\n\
Selection Actions:\n\
\n\
Shift-Button1: Initiate multiple selection.\n\
\n\
Button1: Initiate single selection.\n\
\n\
Button1 Move: Extend current selection.\n\
\n\
Shift-Button2: Clear selection.\n\
\n\
Shift-Button3: Clear all selections.";
XmString message;
XFontStruct *font;
XmFontList font_list = NULL;
Arg arg[2];
int n = 0;
message = XmStringCreateLtoR(help_text, XmSTRING_DEFAULT_CHARSET);
if ((font = XLoadQueryFont(XtDisplay(Toplevel), "*helvetica*14*")) == NULL)
font = XLoadQueryFont(XtDisplay(Toplevel), "fixed");
font_list = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET);
XtSetArg(arg[n], XmNlabelFontList, font_list); n++;
XtSetArg(arg[n], XmNmessageString, message); n++;
message_box = (Widget) XmCreateMessageDialog(Toplevel, "message", arg, n);
XtUnmanageChild((Widget)XmMessageBoxGetChild(message_box, XmDIALOG_CANCEL_BUTTON));
XtUnmanageChild((Widget)XmMessageBoxGetChild(message_box, XmDIALOG_HELP_BUTTON));
XmStringFree(message);
XmFontListFree(font_list);
}
XtManageChild(message_box);
XBell(XtDisplay(message_box), 0);
}
/*ARGSUSED*/
static void
ControlCallback(widget, id, unused)
Widget widget;
int id;
XtPointer unused;
{
if (id == XtNumber(control_names) - 1) exit(0);
switch (id) {
case 0: Help(); break;
default: XtError("Bad control code passed to ControlsProc");
}
}
Click here for the Image
Back to EditTable FAQ
© INT 1996.