/***************************************************************************
 * listwin_pak.c -general-purpose dynamic list-window functions to make    *
 *                programming alot easier.                                 *
 *                (c) 1990 VIDEOWORKS Computer Applications                *
 *                All rights reserved.                                     *
 *                129 Orchard Avenue, Rocky Mount, VA 24151                *                                         *
 *                (703) 483-8219 / 489-3863                                *
 *                                                                         *
 *                Designed and Developed by Paul T. Miller                 *
 *                                                                         *
 * Program Name:  N/A                                                      *
 * Version:       1                                                        *
 * Revision:      0                                                        *
 *-------------------------------------------------------------------------*
 * File: (listwin_pak.c) dynamic list-window package routines              *
 *-------------------------------------------------------------------------*
 * Modification History                                                    *
 * Date     Author   Comment                                               *
 * -------- ------   -------                                               *
 * 06-13-90    PTM   Created.
 * 06-14-90    PTM   Name selection, resizing, scrolling.
 * 06-15-90    PTM   List Sorting. return selected name in a buffer+code
 * 06-15-90    PTM   SHIFT+Key list indexing
 * 06-18-90    PTM   Remove name gadgets - make MOUSEDOWN/position events
 * 06-22-90    PTM   NameList structure/text pointer routines
 * 06-23-90    PTM   Name adding/removing from name lists
 ***************************************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <devices/inputevent.h>
#include <proto/intuition.h>
#include <clib/macros.h>
#include <ctype.h>
#include "listwin_pak.h"

/* ListWindow Gadget constants */
#define ARROW_WIDTH     16
#define ARROW_HEIGHT    13
#define NAME_GAD_HEIGHT 10
#define SIZE_GAD_HEIGHT 8

#define PROP_ID         900
#define ARROW_UP_ID     901
#define ARROW_DOWN_ID   902

#define UP_ARROW        0x4c
#define DOWN_ARROW      0x4d
#define LEFT_ARROW      0x4f
#define RIGHT_ARROW     0x4e

#define SHIFT_KEY       (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)

UWORD chip uparrow_data[1][13][1] = {
    {
        0xffff,0xc003,0xc183,0xc3c3,0xc7e3,0xcff3,0xdffb,0xc3c3,
        0xc3c3,0xc3c3,0xc3c3,0xc003,0xffff
    }
};

UWORD chip downarrow_data[1][13][1] = {
    {
        0xffff,0xc003,0xc3c3,0xc3c3,0xc3c3,0xc3c3,0xdffb,0xcff3,
        0xc7e3,0xc3c3,0xc183,0xc003,0xffff
    }
};

struct ConsoleDevice *ConsoleDevice = NULL;
struct IOStdReq       ioreq;

InitListWindowPackage()
{
   if (OpenDevice("console.device", -1L, (struct IORequest *)&ioreq, 0L))
      return(NULL);
   ConsoleDevice = (struct ConsoleDevice *)ioreq.io_Device;

   return(1);
}

void CloseListWindowPackage()
{
   if (ConsoleDevice) CloseDevice((struct IORequest *)&ioreq);
   ConsoleDevice = NULL;
}

struct Window *OpenListWindow(nw)
struct NewWindow *nw;
{
   struct Window *win;

   win = OpenWindow(nw);
   if (win)
   {
      if (MakeListWindow(win))
         return(win);
   }
   return(NULL);
}

MakeListWindow(win)
struct Window *win;
{
   struct ListWindow *lw;
   ULONG IDCMPflags;

   if (!win) return(NULL);

   /* make sure the correct IDCMP bits are set */
   IDCMPflags = RAWKEY | MOUSEMOVE | GADGETUP | GADGETDOWN | MOUSEBUTTONS;
   if (win->Flags & WINDOWSIZING)
      IDCMPflags |= NEWSIZE;
   if (win->Flags & WINDOWCLOSE)
      IDCMPflags |= CLOSEWINDOW;

   IDCMPflags |= win->IDCMPFlags;

   ReportMouse(win, 1);
   ModifyIDCMP(win, IDCMPflags);

   lw = (struct ListWindow *)AllocMem(LISTWINDOW_SIZE, MEMF_CLEAR);
   if (!lw)
   {
      CloseListWindow(win);
      return(NULL);
   }
   lw->Window = win;

   win->UserData = (BYTE *)lw;

   if (!AllocateListWinGads(lw))
   {
      CloseListWindow(win);
      return(NULL);
   }
   return(1);
}

void CloseListWindow(win)
struct Window *win;
{
   if (win)
   {
      FreeListWindow(win);
      CloseWindow(win);
   }
}

void FreeListWindow(win)
struct Window *win;
{
   struct ListWindow *lw;

   if (win)
   {
      lw = (struct ListWindow *)win->UserData;
      if (lw)
      {
         FreeListWinGads(lw);
         if (lw->NameList) FreeNameList(lw->NameList);
         FreeMem(lw, LISTWINDOW_SIZE);
      }
   }
}

AllocateListWinGads(lw)
struct ListWindow *lw;
{
   struct Gadget *gad;
   struct Image *image;
   struct PropInfo *pinfo;
   SHORT barheight;

   if (!lw || !lw->Window) return(NULL);
   barheight = lw->Window->BorderTop;

   /* allocate and initialize the up-arrow gadget */
   gad = (struct Gadget *)AllocMem(sizeof(struct Gadget), MEMF_CLEAR);
   if (!gad) return(NULL);

   gad->LeftEdge = -(ARROW_WIDTH-1);
   gad->TopEdge = barheight - 1;
   gad->Width = ARROW_WIDTH;
   gad->Height = ARROW_HEIGHT;
   gad->GadgetType = BOOLGADGET;
   gad->Flags = GADGIMAGE|GADGHCOMP|GRELRIGHT;
   gad->Activation = GADGIMMEDIATE|RELVERIFY;
   gad->GadgetText = NULL;
   gad->SelectRender = NULL;
   gad->GadgetID = ARROW_UP_ID;

   lw->UpGad = gad;

   image = (struct Image *)AllocMem(sizeof(struct Image), MEMF_CLEAR);
   if (!image) return(NULL);

   image->Width = ARROW_WIDTH;
   image->Height = ARROW_HEIGHT;
   image->Depth = 1;
   image->ImageData = (USHORT *)&uparrow_data[0];
   image->PlanePick = 0x01;

   lw->UpGad->GadgetRender = (APTR)image;

   /* allocate and initialize the down-arrow gadget */
   gad = (struct Gadget *)AllocMem(sizeof(struct Gadget), MEMF_CLEAR);
   if (!gad) return(NULL);

   movmem(lw->UpGad, gad, sizeof(struct Gadget));
   gad->LeftEdge = -(ARROW_WIDTH-1);
   gad->TopEdge = -ARROW_HEIGHT;
   if (lw->Window->Flags & WINDOWSIZING)
      gad->TopEdge -= SIZE_GAD_HEIGHT;
   gad->Flags |= GRELBOTTOM;
   gad->GadgetID = ARROW_DOWN_ID;

   lw->DownGad = gad;

   image = (struct Image *)AllocMem(sizeof(struct Image), MEMF_CLEAR);
   if (!image) return(NULL);

   image->Width = ARROW_WIDTH;
   image->Height = ARROW_HEIGHT;
   image->Depth = 1;
   image->ImageData = (USHORT *)&downarrow_data[0];
   image->PlanePick = 0x01;

   lw->DownGad->GadgetRender = (APTR)image;

   /* allocate and initialize the proportional gadget */
   gad = (struct Gadget *)AllocMem(sizeof(struct Gadget), MEMF_CLEAR);
   if (!gad) return(NULL);

   gad->LeftEdge = -(ARROW_WIDTH-1);
   gad->TopEdge = barheight + ARROW_HEIGHT - 1;
   gad->Width = ARROW_WIDTH;
   gad->Height = -(ARROW_HEIGHT*2 + barheight);
   if (lw->Window->Flags & WINDOWSIZING)
      gad->Height -= SIZE_GAD_HEIGHT;
   gad->GadgetType = PROPGADGET;
   gad->Flags = GRELRIGHT|GRELHEIGHT;
   gad->Activation = GADGIMMEDIATE|FOLLOWMOUSE|RELVERIFY;
   gad->GadgetText = NULL;
   gad->SelectRender = NULL;
   gad->GadgetID = PROP_ID;

   lw->PropGad = gad;

   /* allocate the PropGadget slider image */
   image = (struct Image *)AllocMem(sizeof(struct Image), MEMF_CLEAR);
   if (!image) return(NULL);

   lw->PropGad->GadgetRender = (APTR)image;

   pinfo = (struct PropInfo *)AllocMem(sizeof(struct PropInfo), MEMF_CLEAR);
   if (!pinfo) return(NULL);

   pinfo->Flags = AUTOKNOB|FREEVERT;
   pinfo->VertPot = 1;
   pinfo->HorizBody = MAXBODY;
   pinfo->VertBody = MAXBODY;

   lw->PropGad->SpecialInfo = (APTR)pinfo;

   lw->UpGad->NextGadget = lw->DownGad;
   lw->DownGad->NextGadget = lw->PropGad;
   lw->PropGad->NextGadget = NULL;

   AddGList(lw->Window, lw->UpGad, -1, 3, NULL);
   RefreshGList(lw->UpGad, lw->Window, NULL, 3);

   return(1);
}

void FreeListWinGads(lw)
struct ListWindow *lw;
{
   struct Gadget *gad;
   struct Image *image;
   struct PropInfo *pinfo;

   if (!lw) return;

   RemoveGList(lw->Window, lw->UpGad, 3);

   if (gad = lw->UpGad)
   {
      image = (struct Image *)gad->GadgetRender;
      if (image) FreeMem(image, sizeof(struct Image));
      FreeMem(gad, sizeof(struct Gadget));
      lw->UpGad = NULL;
   }
   if (gad = lw->DownGad)
   {
      image = (struct Image *)gad->GadgetRender;
      if (image) FreeMem(image, sizeof(struct Image));
      FreeMem(gad, sizeof(struct Gadget));
      lw->DownGad = NULL;
   }
   if (gad = lw->PropGad)
   {
      image = (struct Image *)gad->GadgetRender;
      if (image) FreeMem(image, sizeof(struct Image));
      pinfo = (struct PropInfo *)gad->SpecialInfo;
      if (pinfo) FreeMem(pinfo, sizeof(struct PropInfo));
      FreeMem(gad, sizeof(struct Gadget));
      lw->PropGad = NULL;
   }
}

InitListWindow(win, namelist, names, pos)
struct Window *win;
UBYTE **namelist;
SHORT names, pos;
{
   struct ListWindow *lw;
   struct NameList *nlist = NULL;

   lw = (struct ListWindow *)win->UserData;
   if (!win || !lw) return(NULL);

   /* application supplied a string pointer array, so allocate a NameList */
   if (namelist)
   {
      if (!lw->NameList)
      {
         nlist = AllocateNameList(names);
         if (!nlist)
            return(NULL);
      }
      else
         nlist = lw->NameList;
      SetNameList(nlist, namelist, names);
   }

   lw->Overlap = 1;
   lw->SlotHeight = NAME_GAD_HEIGHT;

   SetListWindowNameList(win, nlist, pos);

   return(1);
}

void SetListWindowNameList(win, nlist, pos)
struct Window *win;
struct NameList *nlist;
SHORT pos;
{
   struct ListWindow *lw;

   lw = (struct ListWindow *)win->UserData;
   if (!win || !lw) return;

   lw->NameList = nlist;
   lw->Selected = -1;

   if (lw->NameList)
   {
      lw->TotalNames = nlist->Names;
      SortNameList(lw->NameList);
   }
   else
      lw->TotalNames = 0;

   SetNameListPos(win, pos);
}

void SetNameListPos(win, pos)
struct Window *win;
SHORT pos;
{
   struct ListWindow *lw;
   SHORT i, x, y, w, h;
   static struct IntuiText itext = {1, 0, JAM1, 1, 1, NULL, (UBYTE *)NULL, NULL};

   lw = (struct ListWindow *)win->UserData;

   if (!win || !lw) return;

   /* clear the name area */
   x = win->BorderLeft;
   y = win->BorderTop;
   w = win->Width - ARROW_WIDTH - 6;
   h = win->Height - y - 2;
   lw->SlotWidth = w;                     /* find width of each name */
   lw->VisibleNum = h / lw->SlotHeight;   /* find total number of slots */

   SetDrMd(win->RPort, JAM1);
   FillBox(win->RPort, x, y, w, h, 0);

   /* now, if there are no names, just leave */
   if (!lw->NameList || lw->NameList->Names == 0) return;

   lw->TopNum = pos;
   lw->Hidden = MAX(lw->TotalNames - lw->VisibleNum, 0);

   if (lw->TopNum > lw->Hidden)
      lw->TopNum = lw->Hidden;

   if (lw->TopNum < 0) lw->TopNum = 0;

   for (i = 0; i < lw->VisibleNum; i++)
   {
      h = i + lw->TopNum;     /* name offset within list */
      y = (i * lw->SlotHeight) + win->BorderTop;   /* in-window position */

      if (i < lw->TotalNames && lw->NameList->NamePtrs[i])
      {
         itext.IText = lw->NameList->NamePtrs[h];
         PrintIText(win->RPort, &itext, x, y);
         if (i == lw->Selected)
         {
            SetDrMd(win->RPort, COMPLEMENT);
            FillBox(win->RPort, x, y, lw->SlotWidth, lw->SlotHeight-1, 1);
         }
      }
   }
   SetListWindowPropGad(lw);
}

void SetListWindowPropGad(lw)
struct ListWindow *lw;
{
   UWORD VertBody, VertPot;

   if (!lw) return;

   if (lw->Hidden > 0 && lw->TotalNames > lw->Overlap)
      VertBody = (UWORD)(((ULONG)(lw->VisibleNum - lw->Overlap) * MAXBODY)/
         (lw->TotalNames - lw->Overlap));
   else
      VertBody = MAXBODY;

   if (lw->Hidden > 0)
      VertPot = (UWORD)(((ULONG)lw->TopNum * MAXPOT) / lw->Hidden);
   else
      VertPot = 0;

   NewModifyProp(lw->PropGad, lw->Window, NULL, AUTOKNOB|FREEVERT,
      MAXPOT, VertPot, MAXBODY, VertBody, 1);
}

UWORD GetListWindowPropValue(win)
struct Window *win;
{
   struct ListWindow *lw;
   struct PropInfo *pinfo;
   UWORD topline;

   lw = (struct ListWindow *)win->UserData;
   if (!win || !lw) return(NULL);

   pinfo = (struct PropInfo *)lw->PropGad->SpecialInfo;

   topline = (UWORD)((((ULONG)lw->Hidden * pinfo->VertPot) + (MAXPOT/2))/
      MAXPOT);

   return(topline);
}

HandleListWindow(message, buffer)
struct IntuiMessage *message;
UBYTE *buffer;
{
   struct Window *win;
   ULONG class;
   USHORT code, qualifier;
   struct Gadget *gadget;
   struct ListWindow *lw;
   SHORT num, mx, my;
   USHORT step = 1;

   if (!message) return(LISTWINDOW_NONE);

   win = message->IDCMPWindow;
   class = message->Class;
   code = message->Code;
   qualifier = message->Qualifier;
   gadget = (struct Gadget *)message->IAddress;
   mx = message->MouseX;
   my = message->MouseY;

   lw = (struct ListWindow *)win->UserData;
   if (!win || !lw) return(LISTWINDOW_NONE);

   if (qualifier & SHIFT_KEY)
      step = lw->VisibleNum - 1;

   switch (class)
   {
      case CLOSEWINDOW:
         return(CLOSE_LISTWINDOW);
         break;
      case RAWKEY:
         if (!ConsoleDevice) break;
         num = HandleListWindowRawKey(win, code, qualifier, (APTR)gadget);
         if (num > -1)
         {
            strcpy(buffer, lw->NameList->NamePtrs[num + lw->TopNum]);
            return(GOT_NAME);
         }
         break;
      case NEWSIZE:
         ResizeListWindow(win);
         break;
      case GADGETDOWN:
         num = HandleListWindowGadgetDown(win, gadget, step);
         if (num > -1)
         {
            strcpy(buffer, lw->NameList->NamePtrs[num + lw->TopNum]);
            return(GOT_NAME);
         }
         break;
      case MOUSEBUTTONS:
         switch (code)
         {
            case SELECTDOWN:
               num = GetListNameSlot(win, mx, my);
               if (num > -1)
               {
                  strcpy(buffer, lw->NameList->NamePtrs[num + lw->TopNum]);
                  return(GOT_NAME);
               }
               break;
            case SELECTUP:
               break;
         }
         break;
   }
   return(LISTWINDOW_NONE);
}

SHORT HandleListWindowRawKey(win, code, qualifier, address)
struct Window *win;
USHORT code, qualifier;
APTR address;
{
   struct ListWindow *lw;
   LONG numchars;
   UBYTE buffer[10];
   USHORT step = 1;

   lw = (struct ListWindow *)win->UserData;

   if (!win || !lw) return(-1);

   buffer[0] = '\0';
   numchars = ConvertRawKey(code, qualifier, address, buffer, 10);

   if (numchars == 0)
      return(-1);

   if (numchars == 1)
      return(HandleListWindowKey(win, buffer[0]));

   if (qualifier & SHIFT_KEY)
      step = lw->VisibleNum - 1;

   switch (code)
   {
      case UP_ARROW:
         return(HandleListWindowGadgetDown(win, lw->UpGad, step));
         break;
      case DOWN_ARROW:
         return(HandleListWindowGadgetDown(win, lw->DownGad, step));
         break;
      case LEFT_ARROW:
         if (lw->TopNum == 0)
            break;
         SetNameListPos(win, 0);
         return(lw->Selected);
         break;
      case RIGHT_ARROW:
         if (lw->TopNum == lw->TotalNames - lw->VisibleNum)
            break;
         SetNameListPos(win, (SHORT)(lw->TotalNames - lw->VisibleNum));
         return(lw->Selected);
         break;
   }
   return(-1);
}

SHORT HandleListWindowKey(win, key)
struct Window *win;
UBYTE key;
{
   struct ListWindow *lw;
   UBYTE *string, *string2;
   USHORT i;

   lw = (struct ListWindow *)win->UserData;

   if (!win || !lw) return(-1);

   if (key && isupper(key))
   {
      string = lw->NameList->NamePtrs[lw->TopNum];     /* already there */
      if (key == toupper(string[0]))
         return(-1);

      for (i = 0; i < lw->TotalNames; i++)
      {
         string = lw->NameList->NamePtrs[i];

         if (key == toupper(string[0]))
         {
            SetNameListPos(win, i);
            return(lw->Selected);
            break;
         }
         if (i < lw->TotalNames - 1)
         {
            string2 = lw->NameList->NamePtrs[i+1];
            if (toupper(string[0]) < key && key < toupper(string2[0]))
               key = toupper(string2[0]);
         }
      }
      /* if letter not in list, must be near end, so just show last page */
      SetNameListPos(win, (SHORT)(lw->TotalNames - lw->VisibleNum));
      return(lw->Selected);
   }
   return(-1);
}

SHORT HandleListWindowGadgetDown(win, gad, step)
struct Window *win;
struct Gadget *gad;
USHORT step;
{
   struct ListWindow *lw;
   struct IntuiMessage *message;
   ULONG class;
   UBYTE mousemoved = NULL;
   SHORT num;

   lw = (struct ListWindow *)win->UserData;

   if (!win || !lw || !gad) return(-1);
   if (!lw->NameList) return(-1);

   switch (gad->GadgetID)
   {
      case ARROW_UP_ID:
         if (lw->TopNum == 0)
            return(-1);
         lw->TopNum -= step;
         SetNameListPos(win, lw->TopNum);
         break;
      case ARROW_DOWN_ID:
         if (lw->TopNum == lw->TotalNames - lw->VisibleNum)
            return(-1);
         lw->TopNum += step;
         SetNameListPos(win, lw->TopNum);
         break;
      case PROP_ID:
         while (1)
         {
            WaitPort(win->UserPort);
            while (message = (struct IntuiMessage *)GetMsg(win->UserPort))
            {
               class = message->Class;
               ReplyMsg((struct Message *)message);

               switch (class)
               {
                  case GADGETUP:
                     num = GetListWindowPropValue(win);
                     if (num != lw->TopNum)
                        SetNameListPos(win, num);
                     return(lw->Selected);
                     break;
                  case MOUSEMOVE:
                     mousemoved = 1;
                     break;
               }
            }
            if (mousemoved)
            {
               mousemoved = NULL;
               num = GetListWindowPropValue(win);
               if (num != lw->TopNum)
                  SetNameListPos(win, num);
            }
         }
         break;
   }
   return(lw->Selected);
}

SHORT GetListNameSlot(win, mx, my)
struct Window *win;
SHORT mx, my;
{
   struct ListWindow *lw;
   SHORT name;

   lw = (struct ListWindow *)win->UserData;

   if (!lw->NameList || lw->NameList->Names == 0)
      return(-1);

   name = (my - win->BorderTop) / lw->SlotHeight;
   if (name >= lw->TotalNames)
      return(-1);

   /* same name clicked twice, so turn it off */
   if (name == lw->Selected)
   {
      lw->Selected = -1;
      SetNameListPos(win, lw->TopNum);
      return(-1);
   }

   lw->Selected = name;
   SetNameListPos(win, lw->TopNum);
   return(name);
}

LONG ConvertRawKey(code, qualifier, address, buffer, buflen)
USHORT code, qualifier;
APTR address;
UBYTE *buffer;
USHORT buflen;
{
   static struct InputEvent ievent = {NULL, IECLASS_RAWKEY, 0, 0, 0};

   ievent.ie_Code = code;
   ievent.ie_Qualifier = qualifier;
   ievent.ie_position.ie_addr = *((APTR*)address);

   return(RawKeyConvert(&ievent, buffer, buflen, NULL));
}

void ResizeListWindow(win)
struct Window *win;
{
   struct ListWindow *lw;

   lw = (struct ListWindow *)win->UserData;

   if (!win || !lw) return;

   lw->Selected = -1;
   SetNameListPos(win, lw->TopNum);
}

struct NameList *AllocateNameList(names)
SHORT names;
{
   struct NameList *nlist;

   nlist = (struct NameList *)AllocMem(NAMELIST_SIZE, MEMF_CLEAR);
   if (!nlist) return(NULL);

   if (!AllocateNameListPtrs(nlist, names))
   {
      FreeMem(nlist, NAMELIST_SIZE);
      return(NULL);
   }
   return(nlist);
}

void FreeNameList(nlist)
struct NameList *nlist;
{
   if (nlist)
   {
      FreeNameListPtrs(nlist);
      FreeMem(nlist, NAMELIST_SIZE);
   }
}

/* allocate an array of pointers to text strings and set to the specified
   NameList structure */
AllocateNameListPtrs(nlist, names)
struct NameList *nlist;
ULONG names;
{
   UBYTE **array;

   array = (UBYTE **)AllocMem(sizeof(APTR)*names, MEMF_CLEAR);
   if (!array)
      return(NULL);

   nlist->NamePtrs = array;
   nlist->Names = 0;
   nlist->MaxNames = names;

   return(1);
}

void FreeNameListPtrs(nlist)
struct NameList *nlist;
{
   if (nlist->NamePtrs)
   {
      FreeMem(nlist->NamePtrs, sizeof(APTR)*nlist->MaxNames);
      nlist->NamePtrs = NULL;
      nlist->Names = 0;
      nlist->MaxNames = 0;
   }
}

/* change the maximum number of the specified NameList's text pointers */
ResizeNameList(nlist, size)
struct NameList *nlist;
ULONG size;
{
   UBYTE **array;
   ULONG names;

   if (nlist->MaxNames == size)     /* same size! */
      return(1);

   array = nlist->NamePtrs;      /* save pointer to old array */
   names = nlist->Names;         /* ...and the used number of slots */

   nlist->NamePtrs = (UBYTE **)AllocMem(sizeof(APTR)*size, MEMF_CLEAR);
   if (!nlist->NamePtrs)
   {
      nlist->NamePtrs = array;
      return(NULL);
   }
   nlist->MaxNames = size;       /* set namelist to new number */
   SetNameList(nlist, array, names);      /* now copy names from old array */
   FreeMem(array, sizeof(APTR) * names);  /* free old array */

   return(1);
}

void SetNameList(nlist, namelist, names)
struct NameList *nlist;
UBYTE **namelist;
ULONG names;
{
   register int i;

   if (nlist && namelist)
   {
      for (i = 0; i < names; i++)
      {
         if (i >= nlist->MaxNames)
         {
            nlist->Names = nlist->MaxNames;
            return;
         }
         nlist->NamePtrs[i] = namelist[i];
      }
      nlist->Names = names;
   }
}

void SortNameList(nlist)
struct NameList *nlist;
{
   /* Lattice-C v5.04 built-in sort */
   tqsort(nlist->NamePtrs, nlist->Names);
}

void AddName(nlist, name)
struct NameList *nlist;
UBYTE *name;
{
   if (nlist->Names == nlist->MaxNames)
   {
      if (!ResizeNameList(nlist, nlist->MaxNames + 5))
         return;
   }
   nlist->NamePtrs[nlist->Names] = name;
   nlist->Names++;
   SortNameList(nlist);
}

void RemoveName(nlist, name)
struct NameList *nlist;
UBYTE *name;
{
   register int i;

   for (i = 0; i < nlist->Names; i++)
      if (strcmp(nlist->NamePtrs[i], name) == NULL)
      {
         while (i < nlist->Names)
         {
            nlist->NamePtrs[i] = nlist->NamePtrs[i+1];
            i++;
         }
         nlist->Names--;
         SortNameList(nlist);
         break;
      }
}

void AddListWindowName(win, name)
struct Window *win;
UBYTE *name;
{
   struct ListWindow *lw;

   lw = (struct ListWindow *)win->UserData;
   if (!win || !lw) return;

   AddName(lw->NameList, name);

   lw->TotalNames = lw->NameList->Names;

   SetNameListPos(win, lw->TopNum);
}

void RemoveListWindowName(win, name)
struct Window *win;
UBYTE *name;
{
   struct ListWindow *lw;

   lw = (struct ListWindow *)win->UserData;
   if (!win || !lw) return;
   if (!lw->NameList || lw->NameList->Names == 0) return;

   RemoveName(lw->NameList, name);

   lw->TotalNames = lw->NameList->Names;

   SetNameListPos(win, lw->TopNum);
}

void SelectListWindowName(win, name)
struct Window *win;
UBYTE *name;
{
   struct ListWindow *lw;
   register int i;

   lw = (struct ListWindow *)win->UserData;
   if (!win || !lw) return;

   if (!lw->NameList || lw->NameList->Names == 0) return;

   if (name == NULL)
      lw->Selected = -1;
   else
      for (i = 0; i < lw->TotalNames; i++)
         if (strcmp(lw->NameList->NamePtrs[i], name) == NULL)
         {
            if (i > lw->VisibleNum)
               lw->TopNum = i;
            lw->Selected = i;
            SetNameListPos(win, lw->TopNum);
            break;
         }
}

void SortListWindowNames(win)
struct Window *win;
{
   struct ListWindow *lw;

   lw = (struct ListWindow *)win->UserData;
   if (!win || !lw) return;
   if (!lw->NameList || lw->NameList->Names == 0) return;

   SortNameList(lw->NameList);
   SetNameListPos(win, lw->TopNum);
}
