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 &ltmath.h>
#include &ltstdio.h>
#include &ltstdlib.h>
#include &ltctype.h>
#include &ltXm/Xm.h>
#include &ltXm/Form.h>
#include &ltXm/MessageB.h>
#include &ltXm/PushBG.h>
#include &ltXm/Separator.h>
#include &ltXm/RowColumn.h>
#include &ltXint/Scroll.h>
#include &ltXint/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 &ltKey&gtosfLeft:                  EditTableEnterCell(Left)\n\
   Shift &ltKey&gtosfRight:                 EditTableEnterCell(Right)\n\
   Shift &ltKey&gtosfUp:                    EditTableEnterCell(Up)\n\
   Shift &ltKey&gtosfDown:                  EditTableEnterCell(Down)\n\
   Shift &ltBtn1Down>:                    EditTableStartSelect(multiple)\n\
   Button1&ltMotion>:                     EditTableExtendSelect()\n\
   Shift &ltBtn2Down>:                    EditTableClearSelection()\n\
   Shift &ltBtn3Down>:                    EditTableClearAllSelections()\n\
   Ctrl &ltBtn1Down>:                     EditTableExtendSelect()";

static char annotation_translations[] =
  "~Ctrl ~Shift ~Meta ~Alt &ltBtn1Down>:  AnnotationStartSelect()\n\
   Shift &ltBtn1Down>:                    AnnotationStartSelect(multiple)\n\
   Button1&ltMotion>:                     AnnotationExtendSelect()\n\
   Ctrl &ltBtn1Down>:                     AnnotationExtendSelect()\n\
   &ltBtn1Up>:                            AnnotationEndSelect()\n\
   Shift &ltBtn2Down>:                    EditTableClearSelection()\n\
   Shift &ltBtn3Down>:                    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-&gtcolumn) {

    case IMPORT_LIST:


      if (cb-&gtcell_value.pointer_value != XintUNDEFINED_POINTER) {
        activity = (ActivityPtr) cb-&gtcell_value.pointer_value;
        cb-&gtdisplay_string = buffer;
        sprintf(cb-&gtdisplay_string, "%02d/%02d/%04d",
                activity-&gtmonth, activity-&gtday, activity-&gtyear);
      }

      break;

    case COST_LIST:

      if (cb-&gtcell_value.double_value == XintUNDEFINED_DOUBLE) return;

      /* You can also allocate the buffer for returning the string */
      cb-&gtdisplay_string = XtMalloc(64 * sizeof(char));

      /* And tell the EditTable to free the string after using it */ 
      cb-&gtto_be_freed    = True;

      value = (double) cb-&gtcell_value.double_value;

      negative = value < 0.0;

      value = fabs(value);
      val   = (int) floor(value);

      if (value >= 1000000.0) {
        if (negative) {
          sprintf(cb-&gtdisplay_string, "$(%d,%03d,%03d.%02d)", val / 1000000,
              (val % 1000000) / 1000, val % 1000, (int) ((value - val) * 100));
        } else {
          sprintf(cb-&gtdisplay_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-&gtdisplay_string, "$(%d,%03d.%02d)", val / 1000,
                  val % 1000, (int) ((value - val) * 100));
        } else {
          sprintf(cb-&gtdisplay_string, "$%d,%03d.%02d", val / 1000,
                  val % 1000, (int) ((value - val) * 100));
        }
      } else {
        if (negative) {
          sprintf(cb-&gtdisplay_string, "$(%d.%02d)", val,
                  (int) ((value - val) * 100));
        } else {
          sprintf(cb-&gtdisplay_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-&gtnew_value_string'.
     More complicate parsing scheme may be needed depending on the
     application.
  */

  switch (cb-&gtcolumn) {

    case IMPORT_LIST:

      activity = (ActivityPtr) cb-&gtcell_value.pointer_value;

      i = 0;
      year_read = month_read = day_read = False;
      while (cb-&gtnew_value_string[i] != '\0') {
        if (isdigit(cb-&gtnew_value_string[i])) {
          if (!month_read) {
            sscanf(&cb-&gtnew_value_string[i], "%d", &k);
            if (k < 1 || k > 12) break;
            activity-&gtmonth = k;
            month_read = True;
          } else if (!day_read) {
            sscanf(&cb-&gtnew_value_string[i], "%d", &k);
            if (!CheckDays(activity-&gtmonth, k)) break;
            activity-&gtday = k;
            day_read = True;
          } else if (!year_read) {
            sscanf(&cb-&gtnew_value_string[i], "%d", &k);
            if (k < 0) break;
            activity-&gtyear = k;
            year_read = True;
          }
          while (isdigit(cb-&gtnew_value_string[i])) i++;
        } else {
          i++;
        }
      }
      if (!(day_read && month_read && year_read)) {
        cb-&gtdoit = 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.