#include <cdk_int.h>
#include <scroller.h>

/*
 * $Author: tom $
 * $Date: 2025/01/09 00:20:21 $
 * $Revision: 1.160 $
 */

/*
 * Declare file local prototypes.
 */
static int createList (CDKSELECTION *selection, CDK_CSTRING2 list, int listSize);
static void drawCDKSelectionList (CDKSELECTION *selection, boolean Box);
static void setViewSize (CDKSELECTION *scrollp, int listSize);
static int maxViewSize (CDKSELECTION *scrollp);

/* Determine how many characters we can shift to the right */
/* before all the items have been scrolled off the screen. */
#define AvailableWidth(w)  ((w)->boxWidth - 2*BorderOf(w) - (w)->maxchoicelen)
#define updateViewWidth(w, widest) \
	(w)->maxLeftChar = (((w)->boxWidth > widest) \
			      ? 0 \
			      : (widest - AvailableWidth(w)))
#define WidestItem(w)      ((w)->maxLeftChar + AvailableWidth(w))

#define SCREENPOS(w,n) (w)->itemPos[n] - (w)->leftChar + scrollbarAdj	/* + BorderOf(w) */

DeclareCDKObjects (SELECTION, Selection, setCdk, Int);

/*
 * This function creates a selection widget.
 */
CDKSELECTION *newCDKSelection (CDKSCREEN *cdkscreen,
			       int xplace,
			       int yplace,
			       int splace,
			       int height,
			       int width,
			       const char *title,
			       CDK_CSTRING2 list,
			       int listSize,
			       CDK_CSTRING2 choices,
			       int choiceCount,
			       chtype highlight,
			       boolean Box,
			       boolean shadow)
{
   /* *INDENT-EQLS* */
   CDKSELECTION *selection      = NULL;
   int widestItem               = -1;
   int parentWidth              = getmaxx (cdkscreen->window);
   int parentHeight             = getmaxy (cdkscreen->window);
   int boxWidth;
   int boxHeight;
   int xpos                     = xplace;
   int ypos                     = yplace;
   int j                        = 0;
   int junk2;
   /* *INDENT-OFF* */
   static const struct { int from; int to; } bindings[] = {
		{ CDK_BACKCHAR, KEY_PPAGE },
		{ CDK_FORCHAR,	KEY_NPAGE },
		{ 'g',		KEY_HOME },
		{ '1',		KEY_HOME },
		{ 'G',		KEY_END },
		{ '<',		KEY_HOME },
		{ '>',		KEY_END },
   };
   /* *INDENT-ON* */

   if (choiceCount <= 0
       || (selection = newCDKObject (CDKSELECTION, &my_funcs)) == NULL
       || (selection->choice = typeCallocN (chtype *, choiceCount + 1)) == NULL
       || (selection->choicelen = typeCallocN (int, choiceCount + 1)) == NULL)
   {
      destroyCDKObject (selection);
      return (NULL);
   }

   setCDKSelectionBox (selection, Box);

   /*
    * If the height is a negative value, the height will
    * be ROWS-height, otherwise, the height will be the
    * given height.
    */
   boxHeight = setWidgetDimension (parentHeight, height, 0);

   /*
    * If the width is a negative value, the width will
    * be COLS-width, otherwise, the width will be the
    * given width.
    */
   boxWidth = setWidgetDimension (parentWidth, width, 0);

   boxWidth = setCdkTitle (ObjOf (selection), title, boxWidth);

   /* Set the box height. */
   if (TitleLinesOf (selection) > boxHeight)
   {
      boxHeight = TitleLinesOf (selection)
	 + MINIMUM (listSize, 8)
	 + 2 * BorderOf (selection);
   }

   selection->maxchoicelen = 0;

   /* Adjust the box width if there is a scroll bar. */
   if (splace == LEFT || splace == RIGHT)
   {
      boxWidth++;
      selection->scrollbar = TRUE;
   }
   else
   {
      selection->scrollbar = FALSE;
   }

   /*
    * Make sure we didn't extend beyond the dimensions of the window.
    */
   selection->boxWidth = (boxWidth > parentWidth ? parentWidth : boxWidth);
   selection->boxHeight = (boxHeight > parentHeight ? parentHeight : boxHeight);

   setViewSize (selection, listSize);

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

   /* Make the selection window */
   selection->win = newwin (selection->boxHeight, selection->boxWidth, ypos, xpos);

   /* Is the window null?? */
   if (selection->win == NULL)
   {
      destroyCDKObject (selection);
      return (NULL);
   }

   /* Turn the keypad on for this window. */
   keypad (selection->win, TRUE);

   /* Create the scrollbar window. */
   if (splace == RIGHT)
   {
      selection->scrollbarWin = subwin (selection->win,
					maxViewSize (selection), 1,
					SCREEN_YPOS (selection, ypos),
					(xpos
					 + selection->boxWidth
					 - BorderOf (selection)
					 - 1));
   }
   else if (splace == LEFT)
   {
      selection->scrollbarWin = subwin (selection->win,
					maxViewSize (selection), 1,
					SCREEN_YPOS (selection, ypos),
					SCREEN_XPOS (selection, xpos));
   }
   else
   {
      selection->scrollbarWin = NULL;
   }

   /* *INDENT-EQLS* Set the rest of the variables */
   ScreenOf (selection)                 = cdkscreen;
   selection->parent                    = cdkscreen->window;
   selection->scrollbarPlacement        = splace;
   selection->maxLeftChar               = 0;
   selection->leftChar                  = 0;
   selection->highlight                 = highlight;
   selection->choiceCount               = choiceCount;
   initExitType (selection);
   ObjOf (selection)->acceptsFocus      = TRUE;
   ObjOf (selection)->inputWindow       = selection->win;
   selection->shadow                    = shadow;

   setCDKSelectionCurrent (selection, 0);

   /* Each choice has to be converted from char * to chtype * */
   for (j = 0; j < choiceCount; j++)
   {
      selection->choice[j] = char2Chtype (choices[j],
					  &selection->choicelen[j],
					  &junk2);
      selection->maxchoicelen = MAXIMUM (selection->maxchoicelen,
					 selection->choicelen[j]);
   }

   /* Each item in the needs to be converted to chtype * */
   widestItem = createList (selection, list, listSize);
   if (widestItem > 0)
   {
      updateViewWidth (selection, widestItem);
   }
   else if (listSize)
   {
      destroyCDKObject (selection);
      return (NULL);
   }

   /* Do we need to create a shadow. */
   if (shadow)
   {
      selection->shadowWin = newwin (boxHeight, boxWidth, ypos + 1, xpos + 1);
   }

   /* Setup the key bindings. */
   for (j = 0; j < (int)SIZEOF (bindings); ++j)
      bindCDKObject (vSELECTION,
		     selection,
		     (chtype)bindings[j].from,
		     getcCDKBind,
		     (void *)(long)bindings[j].to);

   /* Register this baby. */
   registerCDKObject (cdkscreen, vSELECTION, selection);

   /* Return the selection list */
   return (selection);
}

/*
 * Put the cursor on the currently-selected item.
 */
static void fixCursorPosition (CDKSELECTION *selection)
{
   scroller_FixCursorPosition ((CDKSCROLLER *)selection);
}

/*
 * This actually manages the selection widget...
 */
int activateCDKSelection (CDKSELECTION *selection, chtype *actions)
{
   /* Draw the selection list */
   drawCDKSelection (selection, ObjOf (selection)->box);

   if (actions == NULL)
   {
      boolean functionKey;

      for (;;)
      {
	 chtype input;
	 int ret;

	 fixCursorPosition (selection);
	 input = (chtype)getchCDKObject (ObjOf (selection), &functionKey);

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

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

   /* Set the exit type and return. */
   setExitType (selection, 0);
   return 0;
}

/*
 * This injects a single character into the widget.
 */
static int _injectCDKSelection (CDKOBJS *object, chtype input)
{
   CDKSELECTION *selection = (CDKSELECTION *)object;
   CDKSCROLLER *widget = (CDKSCROLLER *)object;
   int ppReturn = 1;
   int ret = unknownInt;
   bool complete = FALSE;

   /* Set the exit type. */
   setExitType (widget, 0);

   /* Draw the widget list */
   drawCDKSelectionList (selection, ObjOf (widget)->box);

   /* Check if there is a pre-process function to be called. */
   if (PreProcessFuncOf (widget) != NULL)
   {
      /* Call the pre-process function. */
      ppReturn = PreProcessFuncOf (widget) (vSELECTION,
					    widget,
					    PreProcessDataOf (widget),
					    input);
   }

   /* Should we continue? */
   if (ppReturn != 0)
   {
      /* Check for a predefined binding. */
      if (checkCDKObjectBind (vSELECTION, widget, input) != 0)
      {
	 checkEarlyExit (widget);
	 complete = TRUE;
      }
      else
      {
	 switch (input)
	 {
	 case KEY_UP:
	    scroller_KEY_UP (widget);
	    break;

	 case KEY_DOWN:
	    scroller_KEY_DOWN (widget);
	    break;

	 case KEY_RIGHT:
	    scroller_KEY_RIGHT (widget);
	    break;

	 case KEY_LEFT:
	    scroller_KEY_LEFT (widget);
	    break;

	 case KEY_PPAGE:
	    scroller_KEY_PPAGE (widget);
	    break;

	 case KEY_NPAGE:
	    scroller_KEY_NPAGE (widget);
	    break;

	 case KEY_HOME:
	    scroller_KEY_HOME (widget);
	    break;

	 case KEY_END:
	    scroller_KEY_END (widget);
	    break;

	 case '$':
	    widget->leftChar = widget->maxLeftChar;
	    break;

	 case '|':
	    widget->leftChar = 0;
	    break;

	 case SPACE:
	    if (selection->mode[widget->currentItem] == 0)
	    {
	       if (selection->selections[widget->currentItem]
		   == (selection->choiceCount - 1))
	       {
		  selection->selections[widget->currentItem] = 0;
	       }
	       else
	       {
		  selection->selections[widget->currentItem]++;
	       }
	    }
	    else
	    {
	       Beep ();
	    }
	    break;

	 case KEY_ESC:
	    setExitType (widget, input);
	    complete = TRUE;
	    break;

	 case KEY_ERROR:
	    setExitType (widget, input);
	    complete = TRUE;
	    break;

	 case KEY_TAB:
	 case KEY_ENTER:
	    setExitType (widget, input);
	    ret = 1;
	    complete = TRUE;
	    break;

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

	 default:
	    break;
	 }
      }

      /* Should we call a post-process? */
      if (!complete && (PostProcessFuncOf (widget) != NULL))
      {
	 PostProcessFuncOf (widget) (vSELECTION,
				     widget,
				     PostProcessDataOf (widget),
				     input);
      }
   }

   if (!complete)
   {
      drawCDKSelectionList (selection, ObjOf (widget)->box);
      setExitType (widget, 0);
   }

   ResultOf (widget).valueInt = ret;
   fixCursorPosition (selection);
   return (ret != unknownInt);
}

/*
 * This moves the selection field to the given location.
 */
static void _moveCDKSelection (CDKOBJS *object,
			       int xplace,
			       int yplace,
			       boolean relative,
			       boolean refresh_flag)
{
   CDKSELECTION *selection = (CDKSELECTION *)object;
   /* *INDENT-EQLS* */
   int currentX = getbegx (selection->win);
   int currentY = getbegy (selection->win);
   int xpos     = xplace;
   int ypos     = yplace;
   int xdiff    = 0;
   int ydiff    = 0;

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

   /* Adjust the window if we need to. */
   alignxy (WindowOf (selection), &xpos, &ypos, selection->boxWidth, selection->boxHeight);

   /* Get the difference. */
   xdiff = currentX - xpos;
   ydiff = currentY - ypos;

   /* Move the window to the new location. */
   moveCursesWindow (selection->win, -xdiff, -ydiff);
   moveCursesWindow (selection->scrollbarWin, -xdiff, -ydiff);
   moveCursesWindow (selection->shadowWin, -xdiff, -ydiff);

   /* Touch the windows so they 'move'. */
   refreshCDKWindow (WindowOf (selection));

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

/*
 * This function draws the selection list.
 */
static void _drawCDKSelection (CDKOBJS *object, boolean Box)
{
   CDKSELECTION *selection = (CDKSELECTION *)object;

   /* Draw in the shadow if we need to. */
   if (selection->shadowWin != NULL)
   {
      drawShadow (selection->shadowWin);
   }

   drawCdkTitle (selection->win, object);

   /* Redraw the list */
   drawCDKSelectionList (selection, Box);
}

static int maxViewSize (CDKSELECTION *widget)
{
   return scroller_MaxViewSize ((CDKSCROLLER *)widget);
}

/*
 * Set variables that depend upon the list-size.
 */
static void setViewSize (CDKSELECTION *widget, int listSize)
{
   scroller_SetViewSize ((CDKSCROLLER *)widget, listSize);
}

/*
 * This function draws the selection list window.
 */
static void drawCDKSelectionList (CDKSELECTION *selection, boolean Box GCC_UNUSED)
{
   /* *INDENT-EQLS* */
   int scrollbarAdj     = (selection->scrollbarPlacement == LEFT) ? 1 : 0;
   int screenPos        = 0;
   int j;
   int selItem          = -1;

   /* If there is to be a highlight, assign it now */
   if (ObjOf (selection)->hasFocus)
      selItem = selection->currentItem;

   /* draw the list... */
   for (j = 0; j < selection->viewSize; j++)
   {
      int xpos = SCREEN_XPOS (selection, 0);
      int ypos = SCREEN_YPOS (selection, j);
      int k;

      /* Draw the empty line. */
      writeBlanks (selection->win, xpos, ypos,
		   HORIZONTAL, 0, getmaxx (selection->win));

      k = j + selection->currentTop;

      /* Draw the element in the selection list. */
      if (k < selection->listSize)
      {
	 screenPos = SCREENPOS (selection, k);

	 /* Draw the selection item. */
	 writeChtypeAttrib (selection->win,
			    (screenPos >= 0) ? screenPos : 1,
			    ypos,
			    selection->item[k],
			    ((k == selItem)
			     ? selection->highlight
			     : A_NORMAL),
			    HORIZONTAL,
			    (screenPos >= 0) ? 0 : (1 - screenPos),
			    selection->itemLen[k]);

	 /* Draw the choice value. */
	 writeChtype (selection->win,
		      xpos + scrollbarAdj,
		      ypos,
		      selection->choice[selection->selections[k]],
		      HORIZONTAL,
		      0,
		      selection->choicelen[selection->selections[k]]);
      }
   }

   /* Determine where the toggle is supposed to be. */
   if (selection->scrollbar)
   {
      selection->togglePos = floorCDK (selection->currentItem * (double)selection->step);
      selection->togglePos = MINIMUM (selection->togglePos,
				      (getmaxy (selection->scrollbarWin) - 1));

      (void)mvwvline (selection->scrollbarWin, 0, 0, CDK_FILLED_BOX, getmaxy (selection->scrollbarWin));
      (void)mvwvline (selection->scrollbarWin,
		      selection->togglePos,
		      0,
		      ' ' | A_REVERSE, selection->toggleSize);
   }

   /* Box it if needed */
   if (ObjOf (selection)->box)
   {
      drawObjBox (selection->win, ObjOf (selection));
   }

   fixCursorPosition (selection);
}

/*
 * This sets the background attribute of the widget.
 */
static void _setBKattrSelection (CDKOBJS *object, chtype attrib)
{
   if (object != NULL)
   {
      CDKSELECTION *widget = (CDKSELECTION *)object;

      wbkgd (widget->win, attrib);
      if (widget->scrollbarWin != NULL)
      {
	 wbkgd (widget->scrollbarWin, attrib);
      }
   }
}

static void destroyInfo (CDKSELECTION *widget)
{
   CDKfreeChtypes (widget->item);
   widget->item = NULL;

   freeAndNull (widget->itemPos);
   freeAndNull (widget->itemLen);
   freeAndNull (widget->selections);
   freeAndNull (widget->mode);
}

/*
 * This function destroys the selection list.
 */
static void _destroyCDKSelection (CDKOBJS *object)
{
   if (object != NULL)
   {
      CDKSELECTION *selection = (CDKSELECTION *)object;

      cleanCdkTitle (object);
      CDKfreeChtypes (selection->choice);
      freeChecked (selection->choicelen);
      destroyInfo (selection);

      /* Clean up the windows. */
      deleteCursesWindow (selection->scrollbarWin);
      deleteCursesWindow (selection->shadowWin);
      deleteCursesWindow (selection->win);

      /* Clean the key bindings. */
      cleanCDKObjectBindings (vSELECTION, selection);

      /* Unregister this object. */
      unregisterCDKObject (vSELECTION, selection);
   }
}

/*
 * This function erases the selection list from the screen.
 */
static void _eraseCDKSelection (CDKOBJS *object)
{
   if (validCDKObject (object))
   {
      CDKSELECTION *selection = (CDKSELECTION *)object;

      eraseCursesWindow (selection->win);
      eraseCursesWindow (selection->shadowWin);
   }
}

/*
 * This function sets a couple of the selection list attributes.
 */
void setCDKSelection (CDKSELECTION *selection,
		      chtype highlight,
		      int *choices,
		      boolean Box)
{
   setCDKSelectionChoices (selection, choices);
   setCDKSelectionHighlight (selection, highlight);
   setCDKSelectionBox (selection, Box);
}

/*
 * This sets the selection list items.
 */
void setCDKSelectionItems (CDKSELECTION *selection, CDK_CSTRING2 list, int listSize)
{
   int widestItem;
   int j = 0;

   widestItem = createList (selection, list, listSize);
   if (widestItem <= 0)
      return;

   /* Clean up the display. */
   for (j = 0; j < selection->viewSize; j++)
   {
      writeBlanks (selection->win,
		   SCREEN_XPOS (selection, 0),
		   SCREEN_YPOS (selection, j),
		   HORIZONTAL, 0, getmaxx (selection->win));
   }

   setViewSize (selection, listSize);
   setCDKSelectionCurrent (selection, 0);

   updateViewWidth (selection, widestItem);
}
int getCDKSelectionItems (CDKSELECTION *selection, char **list)
{
   if (list != NULL)
   {
      int j;

      for (j = 0; j < selection->listSize; j++)
      {
	 list[j] = chtype2Char (selection->item[j]);
      }
   }
   return selection->listSize;
}

/*
 *
 */
void setCDKSelectionTitle (CDKSELECTION *selection, const char *title)
{
   /* Make sure the title isn't null. */
   if (title == NULL)
   {
      return;
   }

   (void)setCdkTitle (ObjOf (selection), title, -(selection->boxWidth + 1));

   setViewSize (selection, selection->listSize);
}
char *getCDKSelectionTitle (CDKSELECTION *selection GCC_UNUSED)
{
   return chtype2Char (*TitleOf (selection));
}

/*
 * This sets the highlight bar.
 */
void setCDKSelectionHighlight (CDKSELECTION *selection, chtype highlight)
{
   selection->highlight = highlight;
}
chtype getCDKSelectionHighlight (CDKSELECTION *selection)
{
   return selection->highlight;
}

/*
 * This sets the default choices for the selection list.
 */
void setCDKSelectionChoices (CDKSELECTION *selection, int *choices)
{
   int j;

   /* Set the choice values in the selection list. */
   for (j = 0; j < selection->listSize; j++)
   {
      if (choices[j] < 0)
      {
	 selection->selections[j] = 0;
      }
      else if (choices[j] > selection->choiceCount)
      {
	 selection->selections[j] = selection->choiceCount - 1;
      }
      else
      {
	 selection->selections[j] = choices[j];
      }
   }
}
int *getCDKSelectionChoices (CDKSELECTION *selection)
{
   return selection->selections;
}

/*
 * This sets a single item's choice value.
 */
void setCDKSelectionChoice (CDKSELECTION *selection, int Index, int choice)
{
   int correctChoice = choice;
   int correctIndex = Index;

   /* Verify that the choice value is in range. */
   if (choice < 0)
   {
      correctChoice = 0;
   }
   else if (choice > selection->choiceCount)
   {
      correctChoice = selection->choiceCount - 1;
   }

   /* Make sure the index isn't out of range. */
   if (correctIndex < 0)
   {
      correctIndex = 0;
   }
   else if (correctIndex > selection->listSize)
   {
      correctIndex = selection->listSize - 1;
   }

   /* Set the choice value. */
   selection->selections[correctIndex] = correctChoice;
}
int getCDKSelectionChoice (CDKSELECTION *selection, int Index)
{
   /* Make sure the index isn't out of range. */
   if (Index < 0)
   {
      return selection->selections[0];
   }
   else if (Index > selection->listSize)
   {
      return selection->selections[selection->listSize - 1];
   }
   else
   {
      return selection->selections[Index];
   }
}

/*
 * This sets the modes of the items in the selection list. Currently
 * there are only two: editable=0 and read-only=1
 */
void setCDKSelectionModes (CDKSELECTION *selection, int *modes)
{
   int j;

   /* Make sure the widget pointer is not null. */
   if (selection == NULL)
   {
      return;
   }

   /* Set the modes. */
   for (j = 0; j < selection->listSize; j++)
   {
      selection->mode[j] = modes[j];
   }
}
int *getCDKSelectionModes (CDKSELECTION *selection)
{
   return selection->mode;
}

/*
 * This sets a single mode of an item in the selection list.
 */
void setCDKSelectionMode (CDKSELECTION *selection, int Index, int mode)
{
   /* Make sure the widget pointer is not null. */
   if (selection == NULL)
   {
      return;
   }

   /* Make sure the index isn't out of range. */
   if (Index < 0)
   {
      selection->mode[0] = mode;
   }
   else if (Index > selection->listSize)
   {
      selection->mode[selection->listSize - 1] = mode;
   }
   else
   {
      selection->mode[Index] = mode;
   }
}
int getCDKSelectionMode (CDKSELECTION *selection, int Index)
{
   /* Make sure the index isn't out of range. */
   if (Index < 0)
   {
      return selection->mode[0];
   }
   else if (Index > selection->listSize)
   {
      return selection->mode[selection->listSize - 1];
   }
   else
   {
      return selection->mode[Index];
   }
}

/*
 * This sets the box attribute of the widget.
 */
void setCDKSelectionBox (CDKSELECTION *selection, boolean Box)
{
   ObjOf (selection)->box = Box;
   ObjOf (selection)->borderSize = Box ? 1 : 0;
}
boolean getCDKSelectionBox (CDKSELECTION *selection)
{
   return ObjOf (selection)->box;
}

/*
 * set/get the current item index
 */
void setCDKSelectionCurrent (CDKSELECTION *selection, int item)
{
   scroller_SetPosition ((CDKSCROLLER *)selection, item);
}

int getCDKSelectionCurrent (CDKSELECTION *selection)
{
   return selection->currentItem;
}

/*
 * methods for generic type methods
 */
static void _focusCDKSelection (CDKOBJS *object)
{
   CDKSELECTION *selection = (CDKSELECTION *)object;

   drawCDKSelectionList (selection, ObjOf (selection)->box);
}

static void _unfocusCDKSelection (CDKOBJS *object)
{
   CDKSELECTION *selection = (CDKSELECTION *)object;

   drawCDKSelectionList (selection, ObjOf (selection)->box);
}

static int createList (CDKSELECTION *selection, CDK_CSTRING2 list, int listSize)
{
   int status = 0;
   int widestItem = 0;

   if (selection->listSize > 0)
   {
      CDKfreeChtypes (selection->item);
      selection->item = NULL;
      freeAndNull (selection->itemLen);
      freeAndNull (selection->itemPos);
      freeAndNull (selection->selections);
      freeAndNull (selection->mode);
   }

   if (listSize >= 0)
   {
      /* *INDENT-EQLS* */
      chtype **newList  = typeCallocN (chtype *, listSize + 1);
      int *newLen       = typeCallocN (int, listSize + 1);
      int *newPos       = typeCallocN (int, listSize + 1);
      int *newSel       = typeCallocN (int, listSize + 1);
      int *newMode      = typeCallocN (int, listSize + 1);

      if (newList != NULL
	  && newLen != NULL
	  && newPos != NULL
	  && newSel != NULL
	  && newMode != NULL)
      {
	 int boxWidth = AvailableWidth (selection);
	 int adjust = selection->maxchoicelen + BorderOf (selection);
	 int j;

	 status = 1;
	 for (j = 0; j < listSize; j++)
	 {
	    newList[j] = char2Chtype (list[j], &newLen[j], &newPos[j]);
	    if (newList[j] == NULL)
	    {
	       status = 0;
	       break;
	    }
	    newPos[j] = justifyString (boxWidth, newLen[j], newPos[j]) + adjust;
	    widestItem = MAXIMUM (widestItem, newLen[j]);
	 }

	 if (status)
	 {
	    destroyInfo (selection);

	    /* *INDENT-EQLS* */
	    selection->listSize   = listSize;
	    selection->item       = newList;
	    selection->itemPos    = newPos;
	    selection->itemLen    = newLen;
	    selection->selections = newSel;
	    selection->mode       = newMode;
	 }
	 else
	 {
	    CDKfreeChtypes (newList);
	    freeChecked (newPos);
	    freeChecked (newLen);
	    freeChecked (newSel);
	    freeChecked (newMode);
	 }
      }
      else
      {
	 CDKfreeChtypes (newList);
	 freeChecked (newPos);
	 freeChecked (newLen);
	 freeChecked (newSel);
	 freeChecked (newMode);
      }
   }
   else
   {
      destroyInfo (selection);
   }

   return status ? widestItem : 0;
}

dummyRefreshData (Selection)

dummySaveData (Selection)
