[BACK]Return to matrix.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / othersrc / dist / cdk

File: [cvs.NetBSD.org] / othersrc / dist / cdk / matrix.c (download)

Revision 1.3, Tue Jan 9 18:41:53 2001 UTC (23 years, 2 months ago) by garbled
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +2 -3 lines

Fix a problem in these widgets where they uncondititonally set the
exitType to either vEARLY_EXIT, or vESCAPE_HIT when returning from a bound
function.  This had the unfortunate effect that when you hit F2 to refresh
the screen in sushi, it would exit out immediately after refreshing the
screen.

This modification allows the programmer to still create an exit-causing
bound function, by simply setting the exitType in the function, as was likely
intended by the author.  Many thanks to Charles Hannum for helping me figure
this out.

This should fix problems noted by itojun on tech-userlevel with the function
keys.

#include <cdk.h>

/*
 * $Author: garbled $
 * $Date: 2001/01/09 18:41:53 $
 * $Revision: 1.3 $
 */

/*
 * Declare file local prototypes.
 */
static void highlightCDKMatrixCell (CDKMATRIX *matrix);
static void CDKMatrixCallBack (CDKMATRIX *matrix, chtype input);
static void drawCDKMatrixCell (CDKMATRIX *matrix,
			int srow, int scol,
			int vrow, int vcol,
			chtype attr, boolean Box);
static void redrawTitles (CDKMATRIX *matrix, int row, int col);

/*
 * Declare file local variables.
 */
extern char *GPasteBuffer;

DeclareCDKObjects(my_funcs,Matrix);

/*
 * This function creates the matrix widget.
 */
CDKMATRIX *newCDKMatrix (CDKSCREEN *cdkscreen, int xplace, int yplace, int rows, int cols, int vrows, int vcols, char *title, char **rowtitles, char **coltitles, int *colwidths, int *colvalues, int rspace, int cspace, chtype filler, int dominant, boolean 


Box, boolean boxCell, boolean shadow)
{
   /* Declare local variables. */
   CDKMATRIX *matrix	= newCDKObject(CDKMATRIX, &my_funcs);
   int parentWidth	= getmaxx(cdkscreen->window);
   int parentHeight	= getmaxy(cdkscreen->window);
   chtype *junk		= 0;
   int boxHeight	= 0;
   int boxWidth		= 0;
   int xpos		= xplace;
   int ypos		= yplace;
   int maxWidth		= INT_MIN;
   int maxRowTitleWidth = 0;
   int rowSpace		= MAXIMUM (0, rspace);
   int colSpace		= MAXIMUM (0, cspace);
   int begx		= 0;
   int begy		= 0;
   int cellWidth	= 0;
   char **temp		= 0;
   int x, y, z, len, junk2;

   /* Make sure that the number of rows/cols/vrows/vcols is not zero. */
   if (rows == 0 || cols == 0 || vrows == 0 || vcols == 0)
   {
      /* Free up any used memory. */
      free (matrix);

      return (0);
   }

  /*
   * Make sure the number of virtual cells is not larger than
   * the physical size.
   */
   vrows = (vrows > rows ? rows : vrows);
   vcols = (vcols > cols ? cols : vcols);

   /* We need to determine the width of the matrix box. */
   if (title != 0)
   {
      temp = CDKsplitString (title, '\n');
      matrix->titleLines = CDKcountStrings (temp);

      for (x=0; x < matrix->titleLines; x++)
      {
	 junk = char2Chtype (temp[x], &len, &junk2);
	 maxWidth = MAXIMUM (maxWidth, len);
	 freeChtype (junk);
      }

      CDKfreeStrings(temp);
   }
   else
   {
      /* No title? Set the required variables. */
      matrix->titleLines = 0;
   }
   boxWidth = maxWidth;

   /* Determine the height of the box. */
   if (vrows == 1)
   {
      boxHeight = 6 + matrix->titleLines;
   }
   else
   {
      if (rowSpace == 0)
      {
	 boxHeight = 6 + matrix->titleLines + ((vrows - 1) * 2);
      }
      else
      {
	 boxHeight = 3 + matrix->titleLines + (vrows * 3) + ((vrows-1) * (rowSpace-1));
      }
   }

   /* Determine the maximum row title width */
   for (x=1; x <= rows; x++)
   {
      matrix->rowtitle[x] = char2Chtype (rowtitles[x], &matrix->rowtitleLen[x], &matrix->rowtitlePos[x]);
      maxRowTitleWidth = MAXIMUM (maxRowTitleWidth, matrix->rowtitleLen[x]);
   }
   matrix->maxrt = maxRowTitleWidth + 2;

   /* We need to rejustify the row title cell info. */
   for (x=1; x <= rows; x++)
   {
      matrix->rowtitlePos[x] = justifyString (matrix->maxrt, matrix->rowtitleLen[x], matrix->rowtitlePos[x]);
   }

   /* Determine the width of the matrix. */
   maxWidth = 2 + matrix->maxrt;
   for (x=1; x <= vcols; x++)
   {
      maxWidth += colwidths[x] + 2 + colSpace;
   }
   maxWidth -= (colSpace-1);
   boxWidth = MAXIMUM (maxWidth, boxWidth);

   /* Translate the char * items to chtype * */
   if (title != 0)
   {
      temp = CDKsplitString (title, '\n');
      matrix->titleLines = CDKcountStrings (temp);

      /* For each line in the title, convert from char * to chtype * */
      for (x=0; x < matrix->titleLines; x++)
      {
	 matrix->title[x]	= char2Chtype (temp[x], &matrix->titleLen[x], &matrix->titlePos[x]);
	 matrix->titlePos[x]	= justifyString (boxWidth, matrix->titleLen[x], matrix->titlePos[x]);
      }

      CDKfreeStrings(temp);
   }

  /*
   * Make sure the dimensions of the window didn't
   * extend beyond the dimensions of the parent window.
   */
   boxWidth = MINIMUM (boxWidth, parentWidth);
   boxHeight = MINIMUM (boxHeight, parentHeight);

   /* Rejustify the x and y positions if we need to. */
   alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);

   /* Make the pop-up window. */
   matrix->win = newwin (boxHeight + !!shadow, boxWidth + !!shadow, ypos, xpos);

   if (matrix->win == 0)
   {
      /* Free up any used memory. */
      for (z=1; z <= rows; z++)
      {
	 freeChtype (matrix->rowtitle[z]);
      }
      free (matrix);

      return (0);
   }

   /* Make the subwindows in the pop-up. */
   begx = xpos;
   begy = ypos + 1 + matrix->titleLines;

   /* Make the 'empty' 0x0 cell. */
   matrix->cell[0][0] = subwin (matrix->win, 3, matrix->maxrt, begy, begx);
   begx += matrix->maxrt + 1;

   /* Make the column titles. */
   for (x=1; x <= vcols; x++)
   {
      cellWidth = colwidths[x] + 3;
      matrix->cell[0][x] = subwin (matrix->win, 1, cellWidth, begy, begx);

      if (matrix->cell[0][x] == 0)
      {
	 goto death;
      }

      begx +=  cellWidth + colSpace - 1;
   }
   begy++;

   /* Make the main cell body */
   for (x=1; x <= vrows; x++)
   {
      /* Make the row titles */
      matrix->cell[x][0] = subwin (matrix->win, 3, matrix->maxrt, begy, xpos+1);

      if (matrix->cell[x][0] == 0)
      {
	 goto death;
      }

      /* Set the start of the x position. */
      begx = xpos + matrix->maxrt + 1;

      /* Make the cells */
      for (y=1; y <= vcols; y++)
      {
	 cellWidth = colwidths[y] + 3;

	 matrix->cell[x][y] = subwin (matrix->win, 3, cellWidth, begy, begx);
	 if (matrix->cell[x][y] == 0)
	 {
	    goto death;
	 }

	 begx += cellWidth + colSpace - 1;
	 keypad (matrix->cell[x][y], TRUE);
      }
      begy += rowSpace + 2;
   }
   keypad (matrix->win, TRUE);

   /* Copy the titles into the structure. */
   for (x=1; x <= cols; x++)
   {
      matrix->coltitle[x]	= char2Chtype (coltitles[x], &matrix->coltitleLen[x], &matrix->coltitlePos[x]);
      matrix->coltitlePos[x]	= justifyString (colwidths[x], matrix->coltitleLen[x], matrix->coltitlePos[x]);
      matrix->colwidths[x]	= colwidths[x];
   }

   /* Make room for the cell information. */
   for (x=1; x <= rows; x++)
   {
      for (y=1; y <= cols; y++)
      {
	 matrix->info[x][y]	= (char *)malloc (sizeof (char) * 256);
	 matrix->colvalues[y]	= colvalues[y];
	 matrix->colwidths[y]	= colwidths[y];
	 cleanChar (matrix->info[x][y], colwidths[y]+1, '\0');
      }
   }

   /* Keep the rest of the info. */
   ScreenOf(matrix)		= cdkscreen;
   ObjOf(matrix)->box		= Box;
   matrix->parent		= cdkscreen->window;
   matrix->rows			= rows;
   matrix->cols			= cols;
   matrix->vrows		= vrows;
   matrix->vcols		= vcols;
   matrix->boxWidth		= boxWidth;
   matrix->boxHeight		= boxHeight;
   matrix->rowSpace		= rowSpace;
   matrix->colSpace		= colSpace;
   matrix->filler		= filler;
   matrix->dominant		= dominant;
   matrix->row			= 1;
   matrix->col			= 1;
   matrix->crow			= 1;
   matrix->ccol			= 1;
   matrix->trow			= 1;
   matrix->lcol			= 1;
   matrix->oldcrow		= 1;
   matrix->oldccol		= 1;
   matrix->oldvrow		= 1;
   matrix->oldvcol		= 1;
   matrix->exitType		= vNEVER_ACTIVATED;
   matrix->boxCell		= boxCell;
   matrix->shadow		= shadow;
   matrix->highlight		= A_REVERSE;
   matrix->ULChar		= ACS_ULCORNER;
   matrix->URChar		= ACS_URCORNER;
   matrix->LLChar		= ACS_LLCORNER;
   matrix->LRChar		= ACS_LRCORNER;
   matrix->HChar		= ACS_HLINE;
   matrix->VChar		= ACS_VLINE;
   matrix->BoxAttrib		= A_NORMAL;
   matrix->callbackfn		= (void *)&CDKMatrixCallBack;
   matrix->preProcessFunction	= 0;
   matrix->preProcessData	= 0;
   matrix->postProcessFunction	= 0;
   matrix->postProcessData	= 0;

   /* Clean the key bindings. */
   cleanCDKObjectBindings (vMATRIX, matrix);

   /* Register this baby. */
   registerCDKObject (cdkscreen, vMATRIX, matrix);

   /* Return the matrix pointer */
   return (matrix);

death:
   /* Free up any used memory. */
   for (y=1; y <= rows; y++)
   {
      freeChtype (matrix->rowtitle[y]);
   }

   /* We have to delete any windows created so far. */
   deleteCursesWindow (matrix->win);
   free (matrix);

   return (0);
}

/*
 * This activates the matrix.
 */
int activateCDKMatrix (CDKMATRIX *matrix, chtype *actions)
{
   /* Declare local variables. */
   int ret;

   /* Draw the matrix */
   drawCDKMatrix (matrix, ObjOf(matrix)->box);

   if (actions == 0)
   {
      chtype input = 0;
      for (;;)
      {
	 /* Get the input. */
	 wrefresh (matrix->cell[matrix->crow][matrix->ccol]);
	 input = wgetch (matrix->cell[matrix->crow][matrix->ccol]);

	 /* Inject the character into the widget. */
	 ret = injectCDKMatrix (matrix, input);
	 if (matrix->exitType != vEARLY_EXIT)
	 {
	    return ret;
	 }
      }
   }
   else
   {
      int length = chlen (actions);
      int x = 0;

      /* Inject each character one at a time. */
      for (x=0; x < length; x++)
      {
	 ret = injectCDKMatrix (matrix, actions[x]);
	 if (matrix->exitType != vEARLY_EXIT)
	 {
	    return ret;
	 }
      }
   }

   /* Set the exit type and exit. */
   matrix->exitType = vEARLY_EXIT;
   return -1;
}

/*
 * This injects a single character into the matrix widget.
 */
int injectCDKMatrix (CDKMATRIX *matrix, chtype input)
{
   /* Declare local variables. */
   int refreshCells	= FALSE;
   int movedCell	= FALSE;
   int charcount	= (int)strlen (matrix->info[matrix->row][matrix->col]);
   int ppReturn		= 1;
   int x, y, diff;

   /* Set the exit type. */
   matrix->exitType = vEARLY_EXIT;

   /* Put the focus on the current cell */
   highlightCDKMatrixCell (matrix);

   /* Check if there is a pre-process function to be called. */
   if (matrix->preProcessFunction != 0)
   {
      /* Call the pre-process function. */
      ppReturn = ((PROCESSFN)(matrix->preProcessFunction)) (vMATRIX, matrix, matrix->preProcessData, input);
   }

   /* Should we continue? */
   if (ppReturn != 0)
   {
      /* Check the key bindings. */
      if (checkCDKObjectBind (vMATRIX, matrix, input) != 0)
      {
	 return -1;
      }
      else
      {
	 switch (input)
	 {
	    case CDK_TRANSPOSE :
		 break;

	    case CDK_BEGOFLINE :
		 break;

	    case CDK_ENDOFLINE :
		 break;

	    case KEY_BACKSPACE :
	    case DELETE :
	    case CONTROL('H') :
	    case KEY_DC :
		 if (matrix->colvalues[matrix->col] == vVIEWONLY)
		 {
		   Beep();
		 }
		 else
		 {
		    if (charcount > 0)
		    {
		       charcount--;
		       mvwdelch (matrix->cell[matrix->crow][matrix->ccol], 1, charcount+1);
		       mvwinsch (matrix->cell[matrix->crow][matrix->ccol], 1, charcount+1, matrix->filler);
		       wnoutrefresh (matrix->cell[matrix->crow][matrix->ccol]);
		       matrix->info[matrix->row][matrix->col][charcount] = '\0';
		    }
		    else
		    {
		       Beep();
		    }
		 }
		 break;

	    case KEY_RIGHT :
	    case KEY_TAB :
		 if (matrix->ccol != matrix->vcols)
		 {
		    /* We are moving to the right... */
		    matrix->col++;
		    matrix->ccol++;
		    movedCell = TRUE;
		 }
		 else
		 {
		    /* We have to shift the columns to the right. */
		    if (matrix->col != matrix->cols)
		    {
		       matrix->lcol++;
		       matrix->col++;
		       redrawTitles (matrix, FALSE, TRUE);
		       refreshCells = TRUE;
		       movedCell = TRUE;
		    }
		    else
		    {
		       /* We are at the far right column, we need  */
		       /* shift down one row, if we can. */
		       if (matrix->row == matrix->rows)
		       {
			  Beep();
		       }
		       else
		       {
			  /* Set up the columns info. */
			  matrix->col  = 1;
			  matrix->lcol = 1;
			  matrix->ccol = 1;

			  /* Shift the rows... */
			  if (matrix->crow != matrix->vrows)
			  {
			     matrix->row++;
			     matrix->crow++;
			  }
			  else
			  {
			     matrix->row++;
			     matrix->trow++;
			     redrawTitles (matrix, TRUE, TRUE);
			     refreshCells = TRUE;
			  }
			  movedCell = TRUE;
		       }
		    }
		 }
		 break;

	    case KEY_LEFT :
		 if (matrix->ccol != 1)
		 {
		    /* We are moving to the left... */
		    matrix->col--;
		    matrix->ccol--;
		    movedCell = TRUE;
		 }
		 else
		 {
		    /* Are we at the far left??? */
		    if (matrix->lcol != 1)
		    {
		       matrix->lcol--;
		       matrix->col--;
		       redrawTitles (matrix, FALSE, TRUE);
		       refreshCells = TRUE;
		       movedCell = TRUE;
		    }
		    else
		    {
		       /* Shift up one line if we can... */
		       if (matrix->row == 1)
		       {
			  Beep();
		       }
		       else
		       {
			  /* Set up the columns info. */
			  matrix->col  = matrix->cols;
			  matrix->lcol = matrix->cols - matrix->vcols + 1;
			  matrix->ccol = matrix->vcols;

			  /* Shift the rows... */
			  if (matrix->crow != 1)
			  {
			     matrix->row--;
			     matrix->crow--;
			  }
			  else
			  {
			     matrix->row--;
			     matrix->trow--;
			     redrawTitles (matrix, TRUE, TRUE);
			     refreshCells = TRUE;
			  }
			  movedCell = TRUE;
		       }
		    }
		 }
		 break;

	    case KEY_UP :
		 if (matrix->crow != 1)
		 {
		    matrix->row--;
		    matrix->crow--;
		    movedCell = TRUE;
		 }
		 else
		 {
		    diff = matrix->trow - 1;
		    if (diff > 0)
		    {
		       matrix->trow--;
		       matrix->row--;
		       redrawTitles (matrix, TRUE, FALSE);
		       refreshCells = TRUE;
		       movedCell = TRUE;
		    }
		    else
		    {
		       Beep();
		    }
		 }
		 break;

	    case KEY_DOWN :
		 if (matrix->crow != matrix->vrows)
		 {
		    matrix->row++;
		    matrix->crow++;
		    movedCell = TRUE;
		 }
		 else
		 {
		    diff = matrix->rows - (matrix->trow + matrix->vrows - 1);
		    if (diff > 0)
		    {
		       matrix->trow++;
		       matrix->row++;
		       redrawTitles (matrix, TRUE, FALSE);
		       refreshCells = TRUE;
		       movedCell = TRUE;
		    }
		    else
		    {
		       Beep();
		    }
		 }
		 break;

	    case KEY_NPAGE :
	    case CONTROL('F') :
		 if (matrix->row < matrix->rows)
		 {
		    diff = matrix->rows - (matrix->trow + matrix->vrows - 1);
		    if (diff > 0)
		    {
		       matrix->trow += MINIMUM (diff, matrix->vrows - 1);
		       redrawTitles (matrix, TRUE, FALSE);
		       refreshCells = TRUE;
		    }
		    matrix->row = MINIMUM (matrix->row + matrix->vrows - 1,
						matrix->rows);
		    matrix->crow = matrix->row - matrix->trow + 1;
		    movedCell = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_PPAGE :
	    case CONTROL('B') :
		 if (matrix->row > 1)
		 {
		    diff = matrix->trow - 1;
		    if (diff > 0)
		    {
		       matrix->trow -= MINIMUM (diff, matrix->vrows - 1);
		       redrawTitles (matrix, TRUE, FALSE);
		       refreshCells = TRUE;
		    }
		    matrix->row = MAXIMUM (matrix->row - matrix->vrows + 1,
						1);
		    matrix->crow = matrix->row - matrix->trow + 1;
		    movedCell = TRUE;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	 case CONTROL('G') :
	      jumpToCell (matrix, -1, -1);
	      drawCDKMatrix (matrix, ObjOf(matrix)->box);
	      break;

	 case CDK_PASTE :
	      if (GPasteBuffer == 0 || (int)strlen (GPasteBuffer) > matrix->colwidths[matrix->ccol])
	      {
		 Beep();
	      }
	      else
	      {
		 strcpy (matrix->info[matrix->trow+matrix->crow-1][matrix->lcol+matrix->ccol-1], GPasteBuffer);
		 drawCDKMatrixCell (matrix, matrix->crow, matrix->ccol, matrix->row, matrix->col, A_NORMAL, matrix->boxCell);
	      }
	      break;

	 case CDK_COPY :
	      freeChar (GPasteBuffer);
	      GPasteBuffer	= copyChar (matrix->info[matrix->trow+matrix->crow-1][matrix->lcol+matrix->ccol-1]);
	      break;

	 case CDK_CUT :
	      freeChar (GPasteBuffer);
	      GPasteBuffer	= copyChar (matrix->info[matrix->trow+matrix->crow-1][matrix->lcol+matrix->ccol-1]);
	      cleanChar (matrix->info[matrix->trow+matrix->crow-1][matrix->lcol+matrix->ccol-1], matrix->colwidths[matrix->lcol+matrix->ccol-1], '\0');
	      drawCDKMatrixCell (matrix, matrix->crow, matrix->ccol, matrix->row, matrix->col, A_NORMAL, matrix->boxCell);
	      break;

	 case CDK_ERASE :
	      cleanChar (matrix->info[matrix->trow+matrix->crow-1][matrix->lcol+matrix->ccol-1], matrix->colwidths[matrix->lcol+matrix->ccol-1], '\0');
	      drawCDKMatrixCell (matrix, matrix->crow, matrix->ccol, matrix->row, matrix->col, A_NORMAL, matrix->boxCell);
	      break;

	 case KEY_RETURN :
	 case KEY_ENTER :
	 case KEY_CR :
	      drawCDKMatrixCell (matrix,
				matrix->oldcrow,
				matrix->oldccol,
				matrix->oldvrow,
				matrix->oldvcol,
				A_NORMAL,
				matrix->boxCell);
	      wrefresh (matrix->cell[matrix->crow][matrix->ccol]);
	      matrix->exitType = vNORMAL;
	      return 0;

	 case KEY_ESC :
	      drawCDKMatrixCell (matrix,
				matrix->oldcrow,
				matrix->oldccol,
				matrix->oldvrow,
				matrix->oldvcol,
				A_NORMAL,
				matrix->boxCell);
	      wrefresh (matrix->cell[matrix->crow][matrix->ccol]);
	      matrix->exitType = vESCAPE_HIT;
	      return -1;

	 case CDK_REFRESH :
	      eraseCDKScreen (ScreenOf(matrix));
	      refreshCDKScreen (ScreenOf(matrix));
	      break;

	 default :
	      ((MATRIXCB)matrix->callbackfn)(matrix, input);
	      break;
	 }
      }

      /* Did we change cells? */
      if (movedCell && !refreshCells)
      {
	 /* un-highlight the old box  */
         drawCDKMatrixCell (matrix,
				matrix->oldcrow,
				matrix->oldccol,
				matrix->oldvrow,
				matrix->oldvcol,
				0,
				matrix->boxCell);
      }

      /* Redraw each cell. */
      if (refreshCells)
      {
	 /* Fill in the cells. */
	 for (x=0; x < matrix->vrows; x++)
	 {
	    for (y=0; y < matrix->vcols; y++)
	    {
	       drawCDKMatrixCell (matrix, x+1, y+1,
					matrix->trow + x,
					matrix->lcol + y,
					A_NORMAL,
					matrix->boxCell);
	    }
	 }
      }

      /* Move to the correct position in the cell. */
      if (refreshCells || movedCell)
      {
	 /* Highlight the new cell. */
	 highlightCDKMatrixCell (matrix);
      }

      wnoutrefresh (matrix->win);

      /* Should we call a post-process? */
      if (matrix->postProcessFunction != 0)
      {
	 ((PROCESSFN)(matrix->postProcessFunction)) (vMATRIX, matrix, matrix->postProcessData, input);
      }
   }

   /* Set the variables we need. */
   matrix->oldcrow	= matrix->crow;
   matrix->oldccol	= matrix->ccol;
   matrix->oldvrow	= matrix->row;
   matrix->oldvcol	= matrix->col;

   /* Set the exit type and exit. */
   matrix->exitType = vEARLY_EXIT;
   return -1;
}

/*
 * This allows the programmer to define their own key mappings.
 */
static void CDKMatrixCallBack (CDKMATRIX *matrix, chtype input)
{
   /* Declare local variables. */
   EDisplayType disptype	= (EDisplayType)matrix->colvalues[matrix->col];
   int charcount		= (int)strlen (matrix->info[matrix->row][matrix->col]);
   chtype newchar		= 0;

   /* Check the types */
   if (disptype == vINT && !isdigit((int)input))
   {
      Beep();
   }
   else if ((disptype == vCHAR || disptype == vUCHAR ||
		disptype == vLCHAR || disptype == vUHCHAR ||
		disptype == vLHCHAR) && isdigit((int)input))
   {
      Beep();
   }
   else if (disptype == vVIEWONLY)
   {
      Beep();
   }
   else
   {
      /* Check the width of the string. */
      if (charcount == matrix->colwidths[matrix->col])
      {
	 Beep();
      }
      else
      {
	 /* We will make any needed adjustments to the case of the character. */
	 newchar = input;
	 if ((disptype == vUCHAR || disptype == vUCHAR ||
		disptype == vUMIXED || disptype == vUHMIXED)
		&& !isdigit((int)input))
	 {
	    newchar = toupper(input);
	 }
	 else if ((disptype == vUCHAR || disptype == vUCHAR ||
			disptype == vUMIXED || disptype == vUHMIXED) &&
			!isdigit((int)input))
	 {
	    newchar = tolower(input);
	 }

	 /* Update the screen. */
	 wmove (matrix->cell[matrix->crow][matrix->ccol], 1, (int)strlen (matrix->info[matrix->row][matrix->col])+1);
	 waddch (matrix->cell[matrix->crow][matrix->ccol], newchar);
	 wrefresh (matrix->cell[matrix->crow][matrix->ccol]);

	 /* Update the character pointer. */
	 matrix->info[matrix->row][matrix->col][charcount++] = newchar;
	 matrix->info[matrix->row][matrix->col][charcount] = '\0';
      }
   }
}

/*
 * Highlight the new field.
 */
static void highlightCDKMatrixCell (CDKMATRIX *matrix)
{
   WINDOW *cell;

   drawCDKMatrixCell (matrix, matrix->crow, matrix->ccol, matrix->row,
			matrix->col, A_BOLD, TRUE);

   /* Move the cursor to the correct position within the cell. */
   cell = matrix->cell[matrix->crow][matrix->ccol];
   if (matrix->colwidths[matrix->ccol] == 1)
   {
      wmove (cell, 1, 1);
   }
   else
   {
      wmove (cell, 1, (int)strlen (matrix->info[matrix->row][matrix->col])+1);
   }
   wnoutrefresh (cell);
}

/*
 * This moves the matrix field to the given location.
 */
static void _moveCDKMatrix (CDKOBJS *object, int xplace, int yplace, boolean relative, boolean refresh_flag)
{
   CDKMATRIX *matrix = (CDKMATRIX *)object;

   /*
    * If this is a relative move, then we will adjust where we want
    * to move to.
    */
   if (relative)
   {
      xplace += getbegx(matrix->win);
      yplace += getbegy(matrix->win);
   }

   /* Adjust the window if we need to. */
   alignxy (WindowOf(matrix), &xplace, &yplace, matrix->boxWidth, matrix->boxHeight);

   /* Move the window to the new location. */
   moveCursesWindow(matrix->win, xplace, yplace);

   /* Redraw the window, if they asked for it. */
   if (refresh_flag)
   {
      drawCDKMatrix (matrix, ObjOf(matrix)->box);
   }
}

/*
 * This draws a cell within a matrix.
 */
static void drawCDKMatrixCell (CDKMATRIX *matrix, int row, int col, int vrow, int vcol, chtype attr, boolean Box)
{
   /* Declare local variables. */
   WINDOW *cell		= matrix->cell[row][col];
   chtype highlight;
   int rows		= matrix->vrows;
   int cols		= matrix->vcols;
   int infolen		= (int)strlen (matrix->info[vrow][vcol]);

   /*
    * Given the dominance of the colors/attributes, we need to set the
    * current cell attribute.
    */
   if (matrix->dominant == ROW)
   {
      highlight = matrix->rowtitle[row][0] & A_ATTRIBUTES;
   }
   else if (matrix->dominant == COL)
   {
      highlight = matrix->coltitle[col][0] & A_ATTRIBUTES;
   }
   else if (vrow == matrix->row && vcol == matrix->col)
   {
      highlight = matrix->highlight;
   }
   else
   {
      highlight = matrix->filler & A_ATTRIBUTES;
   }

   /* Draw in the cell info. */
   mvwhline (cell, 1, 1,
		matrix->filler | highlight, matrix->colwidths[col]);
   writeCharAttrib (cell, 1, 1,
		matrix->info[vrow][vcol], highlight, HORIZONTAL,
		0, MINIMUM (matrix->colwidths[col], infolen));
   wmove (cell, 1, infolen + 1);

   /* Always box the current cell. */
   if (vrow == matrix->row && vcol == matrix->col)
   {
      boxWindow (cell, A_BOLD);
   }
   /* If there is no box, draw blanks around the cell. */
   else if (!Box)
   {
      attrbox (cell, ' ', ' ', ' ', ' ', ' ', ' ', A_NORMAL, FALSE);
   }
   /*
    * If the value of the column spacing is greater than 0 then these
    * are independent boxes.
    */
   else if (matrix->colSpace != 0 && matrix->rowSpace != 0)
   {
      boxWindow (cell, attr);
   }
   else if (matrix->colSpace != 0 && matrix->rowSpace == 0)
   {
      if (row == 1)
      {
	 attrbox (cell, ACS_ULCORNER, ACS_URCORNER,
			ACS_LTEE, ACS_RTEE,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (row > 1 && row < rows)
      {
	 attrbox (cell, ACS_LTEE, ACS_RTEE,
			ACS_LTEE, ACS_RTEE,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (row == rows)
      {
	 attrbox (cell, ACS_LTEE, ACS_RTEE,
			ACS_LLCORNER, ACS_LRCORNER,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
   }
   else if (matrix->colSpace == 0 && matrix->rowSpace != 0)
   {
      if (col == 1)
      {
	 attrbox (cell, ACS_ULCORNER, ACS_TTEE,
			ACS_LLCORNER, ACS_BTEE,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (col > 1 && col < cols)
      {
	 attrbox (cell, ACS_TTEE, ACS_TTEE,
			ACS_BTEE, ACS_BTEE,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (col == cols)
      {
	 attrbox (cell, ACS_TTEE, ACS_URCORNER,
			ACS_BTEE, ACS_LRCORNER,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
   }
   /* Start drawing the matrix. */
   else if (row == 1)
   {
      if (col == 1)
      {
	 /* Draw the top left corner */
	 attrbox (cell, ACS_ULCORNER, ACS_TTEE,
			ACS_LTEE, ACS_PLUS,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (col > 1 && col < cols)
      {
	 /* Draw the top middle box */
	 attrbox (cell, ACS_TTEE, ACS_TTEE,
			ACS_PLUS, ACS_PLUS,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (col == cols)
      {
	 /* Draw the top right corner */
	 attrbox (cell, ACS_TTEE, ACS_URCORNER,
			ACS_PLUS, ACS_RTEE,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
   }
   else if (row > 1 && row < rows)
   {
      if (col == 1)
      {
	 /* Draw the middle left box */
	 attrbox (cell, ACS_LTEE, ACS_PLUS,
			ACS_LTEE, ACS_PLUS,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (col > 1 && col < cols)
      {
	 /* Draw the middle box */
	 attrbox (cell, ACS_PLUS, ACS_PLUS,
			ACS_PLUS, ACS_PLUS,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (col == cols)
      {
	 /* Draw the middle right box */
	 attrbox (cell, ACS_PLUS, ACS_RTEE,
			ACS_PLUS, ACS_RTEE,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
   }
   else if (row == rows)
   {
      if (col == 1)
      {
	 /* Draw the bottom left corner */
	 attrbox (cell, ACS_LTEE, ACS_PLUS,
			ACS_LLCORNER, ACS_BTEE,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (col > 1 && col < cols)
      {
	 /* Draw the bottom middle box */
	 attrbox (cell, ACS_PLUS, ACS_PLUS,
			ACS_BTEE, ACS_BTEE,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
      else if (col == cols)
      {
	 /* Draw the bottom right corner */
	 attrbox (cell, ACS_PLUS, ACS_RTEE,
			ACS_BTEE, ACS_LRCORNER,
			ACS_HLINE, ACS_VLINE,
			attr, FALSE);
      }
   }

   wnoutrefresh (cell);
}

/*
 * This function draws the matrix widget.
 */
static void _drawCDKMatrix (CDKOBJS *object, boolean Box)
{
   CDKMATRIX *matrix = (CDKMATRIX *)object;
   int x, y;

   /* Should we box the matrix??? */
   if (Box)
   {
      attrbox (matrix->win,
		matrix->ULChar, matrix->URChar,
		matrix->LLChar, matrix->LRChar,
		matrix->HChar,	matrix->VChar,
		matrix->BoxAttrib,
	        matrix->shadow);
   }

   /* Draw in the title. */
   for (x=0; x < matrix->titleLines; x++)
   {
      writeChtype (matrix->win,
			matrix->titlePos[x],
			x + 1,
			matrix->title[x],
			HORIZONTAL, 0,
			matrix->titleLen[x]);
   }

   redrawTitles (matrix, TRUE, TRUE);

   /* Draw in the cells.. */
   for (x=0; x < matrix->vrows; x++)
   {
      for (y=0; y < matrix->vcols; y++)
      {
	 drawCDKMatrixCell (matrix, x+1, y+1,
				matrix->trow + x,
				matrix->lcol + y,
				A_NORMAL,
				matrix->boxCell);
      }
   }

   /* Highlight the new cell. */
   highlightCDKMatrixCell (matrix);

   /* Redraw the window. */
   wnoutrefresh (matrix->win);
}

/*
 * This function destroys the matrix widget.
 */
void destroyCDKMatrix (CDKMATRIX *matrix)
{
   /* Declare local variables. */
   int x = 0;
   int y = 0;

   /* Erase the object. */
   eraseCDKMatrix (matrix);

   /* Clear out the title. */
   for (x=0; x < matrix->titleLines; x++)
   {
      freeChtype (matrix->title[x]);
   }

   /* Clear out the col titles. */
   for (x=1; x <= matrix->cols; x++)
   {
      freeChtype (matrix->coltitle[x]);
   }

   /* Clear out the row titles. */
   for (x=1; x <= matrix->rows; x++)
   {
      freeChtype (matrix->rowtitle[x]);
   }

   /* Clear out the matrix cells. */
   for (x=1; x <= matrix->rows; x++)
   {
      for (y=1; y <= matrix->cols; y++)
      {
	 freeChar (matrix->info[x][y]);
      }
   }

   /* Clear the matrix windows. */
   deleteCursesWindow (matrix->win);

   /* Unregister this object. */
   unregisterCDKObject (vMATRIX, matrix);

   /* Finish cleaning up. */
   free (matrix);
}

/*
 * This function erases the matrix widget from the screen.
 */
static void _eraseCDKMatrix (CDKOBJS *object)
{
   CDKMATRIX *matrix = (CDKMATRIX *)object;

   eraseCursesWindow (matrix->win);
}

/*
 * This function sets the values of the matrix widget.
 */
void setCDKMatrix (CDKMATRIX *matrix, char *info[MAX_MATRIX_ROWS][MAX_MATRIX_COLS], int rows, int *subSize)
{
   /* Declare local variables. */
   int x	= 0;
   int y	= 0;

   /* Clear out all the cells. */
   for (x=1; x <= matrix->rows; x++)
   {
      for (y=1; y <= matrix->cols; y++)
      {
	 /* Clean the old info, and copy in the new. */
	 if (matrix->info[x][y] != 0)
	 {
	    /* Clean the cell information. */
	    cleanChar (matrix->info[x][y], matrix->colwidths[y], '\0');
	 }
      }
   }

   /* Copy in the new info. */
   for (x=1; x <= rows; x++)
   {
      for (y=1; y <= subSize[x]; y++)
      {
	 /* Copy in the new information. */
	 if (info[x][y] != 0)
	 {
	    strncpy (matrix->info[x][y], info[x][y], matrix->colwidths[y]);
	 }
      }
   }
}

/*
 * This cleans out the information cells in the matrix widget.
 */
void cleanCDKMatrix (CDKMATRIX *matrix)
{
   /* Declare local variables. */
   int x	= 0;
   int y	= 0;

   for (x=1; x <= matrix->rows; x++)
   {
      for (y=1; y <= matrix->cols; y++)
      {
	 cleanChar (matrix->info[x][y], matrix->colwidths[y], '\0');
      }
   }
}

/*
 * This allows us to hyper-warp to a cell.
 */
int jumpToCell (CDKMATRIX *matrix, int row, int col)
{
   /* Declare local variables. */
   CDKSCALE *scale	= 0;
   int newRow		= row;
   int newCol		= col;

  /*
   * Only create the row scale if needed.
   */
   if ((row == -1) || (row > matrix->rows))
   {
      /* Create the row scale widget. */
      scale = newCDKScale (ScreenOf(matrix),
				CENTER, CENTER,
				"<C>Jump to which row.",
				"</5/B>Row: ", A_NORMAL, 5,
				1, 1, matrix->rows, 1, 1, TRUE, FALSE);

      /* Activate the scale and get the row. */
      newRow = activateCDKScale (scale, 0);
      destroyCDKScale (scale);
   }

  /*
   * Only create the column scale if needed.
   */
   if ((col == -1) || (col > matrix->cols))
   {
      /* Create the column scale widget. */
      scale = newCDKScale (ScreenOf(matrix),
				CENTER, CENTER,
				"<C>Jump to which column",
				"</5/B>Col: ", A_NORMAL, 5,
				1, 1, matrix->cols, 1, 1, TRUE, FALSE);

      /* Activate the scale and get the column. */
      newCol = activateCDKScale (scale, 0);
      destroyCDKScale (scale);
   }

   /* Hyper-warp.... */
   if (newRow != matrix->row || newCol != matrix->col)
   {
      return (moveToCDKMatrixCell (matrix, newRow, newCol));
   }
   else
   {
      return 1;
   }
}

/*
 * This allows us to move to a given cell.
 */
int moveToCDKMatrixCell (CDKMATRIX *matrix, int newrow, int newcol)
{
   /* Declare local variables. */
   int rowShift = newrow - matrix->row;
   int colShift = newcol - matrix->col;

   /* Make sure we arent asking to move out of the matrix. */
   if (newrow > matrix->rows || newcol > matrix->cols || newrow <= 0 || newcol <= 0)
   {
      return 0;
   }

   /* Did we move up/down???? */
   if (rowShift > 0)
   {
      /* We are moving down. */
      if (matrix->vrows == matrix->cols)
      {
	 matrix->trow	= 1;
	 matrix->crow	= newrow;
	 matrix->row	= newrow;
      }
      else
      {
	 if ((rowShift + matrix->vrows) < matrix->rows)
	 {
	    /* Just shift down by rowShift... */
	    matrix->trow	+= rowShift;
	    matrix->crow	= 1;
	    matrix->row		+= rowShift;
	 }
	 else
	 {
	    /* We need to munge with the values... */
	    matrix->trow	= matrix->rows - matrix->vrows + 1;
	    matrix->crow	= ((rowShift + matrix->vrows) - matrix->rows) + 1;
	    matrix->row		= newrow;
	 }
      }
   }
   else if (rowShift < 0)
   {
      /* We are moving up. */
      if (matrix->vrows == matrix->rows)
      {
	 matrix->trow	= 1;
	 matrix->row	= newrow;
	 matrix->crow	= newrow;
      }
      else
      {
	 if ((rowShift + matrix->vrows) > 1)
	 {
	    /* Just shift up by rowShift... */
	    matrix->trow	+= rowShift;
	    matrix->row		+= rowShift;
	    matrix->crow	= 1;
	 }
	 else
	 {
	    /* We need to munge with the values... */
	    matrix->trow	= 1;
	    matrix->crow	= 1;
	    matrix->row		= 1;
	 }
      }
   }

   /* Did we move left/right ???? */
   if (colShift > 0)
   {
      /* We are moving right. */
      if (matrix->vcols == matrix->cols)
      {
	 matrix->lcol	= 1;
	 matrix->ccol	= newcol;
	 matrix->col	= newcol;
      }
      else
      {
	 if ((colShift + matrix->vcols) < matrix->cols)
	 {
	    matrix->lcol	+= colShift;
	    matrix->ccol	= 1;
	    matrix->col		+= colShift;
	 }
	 else
	 {
	    /* We need to munge with the values... */
	    matrix->lcol	= matrix->cols - matrix->vcols + 1;
	    matrix->ccol	= ((colShift + matrix->vcols) - matrix->cols) + 1;
	    matrix->col		= newcol;
	 }
      }
   }
   else if (colShift < 0)
   {
      /* We are moving left. */
      if (matrix->vcols == matrix->cols)
      {
	    matrix->lcol	= 1;
	    matrix->col		= newcol;
	    matrix->ccol	= newcol;
      }
      else
      {
	 if ((colShift + matrix->vcols) > 1)
	 {
	    /* Just shift left by colShift... */
	    matrix->lcol	+= colShift;
	    matrix->col		+= colShift;
	    matrix->ccol	= 1;
	 }
	 else
	 {
	    matrix->lcol	= 1;
	    matrix->col		= 1;
	    matrix->ccol	= 1;
	 }
      }
   }

   /* Keep the 'old' values around for redrawing sake. */
   matrix->oldcrow	= matrix->crow;
   matrix->oldccol	= matrix->ccol;
   matrix->oldvrow	= matrix->row;
   matrix->oldvcol	= matrix->col;

   /* Lets ... */
   return 1;
}

/*
 * This redraws the titles indicated...
 */
static void redrawTitles (CDKMATRIX *matrix, int rowTitles, int colTitles)
{
   /* Declare local variables. */
   int x;
   WINDOW *cell;

   /* Redraw the row titles. */
   if (rowTitles)
   {
      for (x=0; x < matrix->vrows; x++)
      {
	 cell = matrix->cell[x+1][0];
	 werase (cell);
	 writeChtype (cell,
			matrix->rowtitlePos[matrix->trow + x], 1,
			matrix->rowtitle[matrix->trow + x],
			HORIZONTAL,
			0, matrix->rowtitleLen[matrix->trow + x]);
	 wnoutrefresh (cell);
      }
   }

   /* Redraw the column titles. */
   if (colTitles)
   {
      for (x=0; x < matrix->vcols; x++)
      {
	 cell = matrix->cell[0][x+1];
	 werase (cell);
	 writeChtype (cell,
			matrix->coltitlePos[matrix->lcol + x], 0,
			matrix->coltitle[matrix->lcol + x],
			HORIZONTAL,
			0, matrix->coltitleLen[matrix->lcol + x]);
	 wnoutrefresh (cell);
      }
   }
}

/*
 * This sets the value of a matrix cell.
 */
int setCDKMatrixCell (CDKMATRIX *matrix, int row, int col, char *value)
{
   /* Make sure the row/col combination is within the matrix. */
   if (row > matrix->rows || col > matrix->cols || row <= 0 || col <= 0)
   {
      return -1;
   }

   /* Clean out the old value. */
   cleanChar (matrix->info[row][col], matrix->colwidths[col]+1, '\0');

   /* Copy the new version in and return. */
   strncpy (matrix->info[row][col], value, matrix->colwidths[col]);
   return 1;
}

/*
 * This gets the value of a matrix cell.
 */
char *getCDKMatrixCell (CDKMATRIX *matrix, int row, int col)
{
   /* Make sure the row/col combination is within the matrix. */
   if (row > matrix->rows || col > matrix->cols || row <= 0 || col <= 0)
   {
      return 0;
   }
   return matrix->info[row][col];
}

/*
 * This returns the current row/col cell.
 */
int getCDKMatrixCol (CDKMATRIX *matrix)
{
   return matrix->col;
}
int getCDKMatrixRow (CDKMATRIX *matrix)
{
   return matrix->row;
}

/*
 * These functions set the drawing characters of the widget.
 */
void setCDKMatrixULChar (CDKMATRIX *matrix, chtype character)
{
   matrix->ULChar = character;
}
void setCDKMatrixURChar (CDKMATRIX *matrix, chtype character)
{
   matrix->URChar = character;
}
void setCDKMatrixLLChar (CDKMATRIX *matrix, chtype character)
{
   matrix->LLChar = character;
}
void setCDKMatrixLRChar (CDKMATRIX *matrix, chtype character)
{
   matrix->LRChar = character;
}
void setCDKMatrixVerticalChar (CDKMATRIX *matrix, chtype character)
{
   matrix->VChar = character;
}
void setCDKMatrixHorizontalChar (CDKMATRIX *matrix, chtype character)
{
   matrix->HChar = character;
}
void setCDKMatrixBoxAttribute (CDKMATRIX *matrix, chtype character)
{
   matrix->BoxAttrib = character;
}

/*
 * This sets the background color of the widget.
 */
void setCDKMatrixBackgroundColor (CDKMATRIX *matrix, char *color)
{
   chtype *holder = 0;
   int x, y, junk1, junk2;

   if (color == 0)
   {
      return;
   }

   /* Convert the value of the environment variable to a chtype. */
   holder = char2Chtype (color, &junk1, &junk2);

   /* Set the widgets background color. */
   wbkgd (matrix->win, holder[0]);
   for (x=0; x <= matrix->vrows; x++)
   {
      for (y=0; y <= matrix->vcols; y++)
      {
	 wbkgd (matrix->cell[x][y], holder[0]);
      }
   }

   /* Clean up. */
   freeChtype (holder);
}

/*
 * This function sets the pre-process function.
 */
void setCDKMatrixPreProcess (CDKMATRIX *matrix, PROCESSFN callback, void *data)
{
   matrix->preProcessFunction = callback;
   matrix->preProcessData = data;
}

/*
 * This function sets the post-process function.
 */
void setCDKMatrixPostProcess (CDKMATRIX *matrix, PROCESSFN callback, void *data)
{
   matrix->postProcessFunction = callback;
   matrix->postProcessData = data;
}