#include <exec/types.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <libraries/commodities.h> /* This has a nice qualifier #define */
#include <graphics/displayinfo.h>
#include <graphics/gfxbase.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/dos.h>  /* Delay() for debugging */

#include <string.h>
#include <stdlib.h>     /* malloc & free */
#include <stdio.h>      /* debugging */

#include "db.h"
#include "Select_P.h"
#include "dbparser.h"
#include "dbGUI.h"      /* We use db's font instead of the screen font */

#define MARGIN 4
#define TOGGLE_LED *(UBYTE *)0xbfe001 ^= 2

extern struct Pro *CurrentPro;

/* We use db's font engine instead.
static struct TextAttr       *Font, Attr;
static UWORD                  FontX, FontY;
*/


/*
void FlashLed(void)
{
        int i;
        for (i=0; i<20; i++) {
                TOGGLE_LED;
                Delay(10);
        }
}
*/

/**********************************************************************/
/*                         Support functions                          */
/**********************************************************************/


static UWORD ComputeX( UWORD value )
{
        return(( UWORD )((( FontX * value ) + 4 ) / 8 ));
}

static UWORD ComputeY( UWORD value )
{
        return(( UWORD )((( FontY * value ) + 6 ) / 13 ));
}
/*
static void ComputeFont( UWORD width, UWORD height )
{
        static UWORD                  OffX, OffY;
        Font = &Attr;
        Font->ta_Name = (STRPTR)Scr->RastPort.Font->tf_Message.mn_Node.ln_Name;
        Font->ta_YSize = FontY = Scr->RastPort.Font->tf_YSize;
        FontX = Scr->RastPort.Font->tf_XSize;

        OffX = Scr->WBorLeft;
        OffY = Scr->RastPort.TxHeight + Scr->WBorTop + 1;

        if ( width && height ) {
                if (( ComputeX( width ) + OffX + Scr->WBorRight ) > Scr->Width )
                        goto UseTopaz;
                if (( ComputeY( height ) + OffY + Scr->WBorBottom ) > Scr->Height )
                        goto UseTopaz;
        }
        return;

UseTopaz:
        Font->ta_Name = (STRPTR)"topaz.font";
        FontX = FontY = Font->ta_YSize = 8;
}
*/


static void MyCreateAllGadgets(Select *s)
{
        struct Gadget   *g;
        static struct NewGadget ng[] =
               {
               4,   4,  213, 229, NULL       , NULL, GD_SELLview, 0, NULL, (APTR)SELLviewClicked,
               4, 232,  213, 229, (char *)"+", NULL, GD_SELLadd , 0, NULL, (APTR)SELLaddClicked,
               4,   4,  213, 229, (char *)"-", NULL, GD_SELLdel , 0, NULL, (APTR)SELLdelClicked
               };

        g = CreateContext( &s->SelGList );


        // listview

        ng[0].ng_VisualInfo = VisualInfo;
        ng[0].ng_TextAttr   = Font;
        ng[0].ng_LeftEdge   = s->SelWnd->BorderLeft + MARGIN;
        ng[0].ng_TopEdge    = s->SelWnd->BorderTop + MARGIN;
        ng[0].ng_Width      = s->SelWnd->Width - s->SelWnd->BorderLeft - s->SelWnd->BorderRight - 2*MARGIN;
        ng[0].ng_Height     = (s->SelWnd->Height - s->SelWnd->BorderTop - s->SelWnd->BorderBottom - 2*MARGIN) - (2*MARGIN + FontY);


        // button +

        ng[1].ng_VisualInfo = VisualInfo;
        ng[1].ng_TextAttr   = Font;
        ng[1].ng_LeftEdge   = s->SelWnd->BorderLeft + MARGIN;
        ng[1].ng_TopEdge    = s->SelWnd->BorderTop + ng[0].ng_Height + 2*MARGIN;
        ng[1].ng_Width      = (s->SelWnd->Width/2) - 2*MARGIN;
        ng[1].ng_Height     = FontY +4;

        // button -

        ng[2].ng_VisualInfo = VisualInfo;
        ng[2].ng_TextAttr   = Font;
        ng[2].ng_LeftEdge   = s->SelWnd->BorderLeft + ng[1].ng_Width + MARGIN + 1;
        ng[2].ng_TopEdge    = ng[1].ng_TopEdge;
        ng[2].ng_Width      = ng[1].ng_Width;
        ng[2].ng_Height     = ng[1].ng_Height;


        s->ListView = g = CreateGadget(LISTVIEW_KIND, g, &ng[0],
                GTLV_Labels, &s->SelList,
                GTLV_ShowSelected, NULL,
                GTLV_Selected, s->SelIndex,
                GTLV_MakeVisible, s->SelIndex,
                TAG_DONE);

        g = CreateGadget(BUTTON_KIND, g, &ng[1],
                GT_Underscore, '_',
                TAG_DONE);

        g = CreateGadget(BUTTON_KIND, g, &ng[2],
                GT_Underscore, '_',
                TAG_DONE);


        AddGList(s->SelWnd, s->SelGList, -1, -1, NULL);
        RefreshWindowFrame(s->SelWnd);
        RefreshGList(s->SelGList, s->SelWnd, NULL, -1);
        GT_RefreshWindow( s->SelWnd, NULL ); /* Must also be called */
}




static void UpdateListView(Select *s)
{
        if (GadToolsBase->lib_Version < 39) {
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL,
                GTLV_Selected, s->SelIndex,
                GTLV_Top, s->SelIndex,
                TAG_END);
        }
        else {
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL,
                GTLV_Selected, s->SelIndex,
                GTLV_MakeVisible, s->SelIndex,
                TAG_END);
        }
}

static struct Node *FindIndex(struct List *list, int idx)
{
        /* Returns the node with index idx in the list, (first node is 0) */
        struct Node *cn;        /* Current Node */
        for (cn = list->lh_Head; idx; cn = cn->ln_Succ, idx--);
        return cn;
}

static int IndexInList(struct List *list, char *str)
{
        /* returs -1 if str doesn't match somewhere in list */
        int len = strlen(str);
        struct Node *node;
        int i;
        for (node = list->lh_Head, i=0;
                node->ln_Succ && Strnicmp(str, node->ln_Name, len);
                node = node->ln_Succ, i++);
        if (node->ln_Succ) return i;
        return -1;
}

static int NextMatch(struct Node *cnode, char *str)
{
        /* returs -1 if str doesn't match somewhere in list */
        int len = strlen(str);
        struct Node *node;
        int i;
        if (!cnode->ln_Succ) return -1;
        for (node = cnode->ln_Succ, i=1;
                node->ln_Succ && Strnicmp(str, node->ln_Name, len);
                node = node->ln_Succ, i++);
        if (node->ln_Succ) return i;
        return -1;
}

static int PrevMatch(struct Node *cnode, char *str)
{
        /* returs -1 if str doesn't match somewhere in list */
        int len = strlen(str);
        struct Node *node;
        int i;
        if (!cnode->ln_Pred) return -1;
        for (node = cnode->ln_Pred, i=1;
                node->ln_Pred && Strnicmp(str, node->ln_Name, len);
                node = node->ln_Pred, i++);
        if (node->ln_Pred) return i;
        return -1;
}


/**********************************************************************/
/*                           Event handlers                           */
/**********************************************************************/


static int SelNewSize(Select *s)
{
        /* routine for "IDCMP_NEWSIZE". */

        RemoveGList(s->SelWnd, s->SelGList, -1);
        FreeGadgets(s->SelGList);

        EraseRect(s->SelWnd->RPort, s->SelWnd->BorderLeft, s->SelWnd->BorderTop,
             s->SelWnd->Width - s->SelWnd->BorderRight, s->SelWnd->Height - s->SelWnd->BorderBottom);

        MyCreateAllGadgets(s);

        return SEL_PRIVATE;
}

static int SELOkClicked(Select *s)
{
        /* routine when gadget "_Ok" is clicked. */
        /* CloseSelect(s); */
        return SEL_OK;
}

static int SELLaddClicked(Select *s)
{
struct FldInfo *f, *last = NULL;


        // lets create the new one...

        if(!(f = NewFldInfo()))
           {
           DisplayBeep(0);
           return MEM_ERR;
           }
        strcpy(f->Name, "New");

        // let's find the last one
        // and attach the new to the list

        if(CurrentPro->FirstFldInfo)
          {
          char tmp[5];
          int Count=1;

          for(last = CurrentPro->FirstFldInfo; last->Next; last = last->Next,Count++);

          sprintf(tmp, "_%ld", Count);

          strcat(f->Name, tmp);
          last->Next = f;
          }
        else
          CurrentPro->FirstFldInfo = f;

        AddStringLast(s, f->Name);

        return(SEL_PRIVATE);
}

static int SELLdelClicked(Select *s)
{

        DoASCIIParsing();
    return(SEL_PRIVATE);
}



static int SELLviewClicked(Select *s)
{
        /* routine when listview gadget is clicked. */

        /* Handle doubleclicks.. */
        if (DoubleClick(s->StartSecs, s->StartMicros, s->SelMsg.Seconds, s->SelMsg.Micros)
                 && s->SelMsg.Code == s->SelIndex) {
                s->StartSecs = s->StartMicros = 0;      /* Prevent "triple clicks" */
                s->SelIndex = s->SelMsg.Code;
                return SELOkClicked(s);
        }
        else {
                s->StartSecs = s->SelMsg.Seconds;
                s->StartMicros = s->SelMsg.Micros;
                s->SelIndex = s->SelMsg.Code;
        }
        return SEL_SELECT;
}

static int SelCloseWindow(Select *s)
{
        /* routine for "IDCMP_CLOSEWINDOW". */
        CloseSelect(s);
        return SEL_CANCEL;
}

static int SELCancelClicked(Select *s)
{
        /* routine when gadget "_Cancel" is clicked. */
        return SelCloseWindow(s);
}


static int SelVanillaKey(Select *s)
{
        /* routine for "IDCMP_VANILLAKEY". */
        int len;
        int index;
        struct List *list = (struct List *) &s->SelList;

        switch (s->SelMsg.Code) {
                case '\r' :
                        return SELOkClicked(s);
                        break;
                case VANILLA_ESC :
                        return SELCancelClicked(s);
                        break;

                case VANILLA_DEL :
                        s->SelCompleteBuf[1] = '\0';
                case '\b' :
                        if (len = strlen(s->SelCompleteBuf)) {
                                s->SelCompleteBuf[len-1] = '\0';
                                if ((index = IndexInList(list, s->SelCompleteBuf)) >= 0) {
                                        s->SelIndex = index;
                                        UpdateListView(s);
                                }
                        }
                        SetWindowTitles(s->SelWnd, s->SelWdt ,(UBYTE *)-1);
                        break;
                case '\t' :
                        if ((index = NextMatch(FindIndex(list, s->SelIndex), s->SelCompleteBuf)) >= 0) {
                                        s->SelIndex += index;
                                        UpdateListView(s);
                                } else DisplayBeep(Scr);
                        break;

                default :
                        if ((len = strlen(s->SelCompleteBuf)) < COMPLETEBUFSIZ-1 ) {
                                s->SelCompleteBuf[len] = s->SelMsg.Code;
                                s->SelCompleteBuf[len+1] = '\0';
                                if ((index = IndexInList(list, s->SelCompleteBuf)) >= 0) {
                                        s->SelIndex = index;
                                        UpdateListView(s);
                                        SetWindowTitles(s->SelWnd, s->SelWdt ,(UBYTE *)-1);
                                }
                                else {
                                        s->SelCompleteBuf[len] = '\0';
                                        DisplayBeep(Scr);
                                }
                        }
                        break;
        }
        return SEL_SELECT;
}

static int SelRawKey(Select *s)
{
        /* routine for "IDCMP_RAWKEY". */

        int index;
        struct List *list = (struct List *)&s->SelList;

        int rows = (s->ListView->Height-4)/FontY;        /* Rows visible in listview. Ugly but works */

        switch (s->SelMsg.Code) {
                case RAW_UP :
                        if (s->SelIndex == 0) return SEL_PRIVATE;
                        if (s->SelMsg.Qualifier & IXSYM_ALTMASK)
                                s->SelIndex = 0;
                        else if (s->SelMsg.Qualifier & IXSYM_SHIFTMASK) {
                                s->SelIndex -= rows-1;
                                if (s->SelIndex < 0) s->SelIndex = 0;
                        }
                        else s->SelIndex--;

                        break;
                case RAW_DOWN :
                        if (s->SelIndex >= s->SelTotal-1) return SEL_PRIVATE;
                        if (s->SelMsg.Qualifier & IXSYM_ALTMASK)
                                 s->SelIndex = s->SelTotal - 1;
                        else if (s->SelMsg.Qualifier & IXSYM_SHIFTMASK) {
                                s->SelIndex += rows-1;
                                if (s->SelIndex > s->SelTotal-1) s->SelIndex = s->SelTotal - 1;
                        }
                        else s->SelIndex++;
                        break;
                case RAW_TAB :
                        if ((index = PrevMatch(FindIndex(list, s->SelIndex), s->SelCompleteBuf)) >= 0) {
                                        s->SelIndex -= index;
                                        UpdateListView(s);
                                } else DisplayBeep(Scr);
                        break;
                case RAW_HELP :
                        return SEL_HELP;
                        break;
                default :
                        return SEL_PRIVATE;
        }

        UpdateListView(s);
        return SEL_SELECT;
}


/**********************************************************************/
/*                        Interface functions                         */
/**********************************************************************/

BOOL FixSelectSize(Select *s, int n)
{
        /* Makes the Select object allocate memory for n elements in one chunk for */
        /* all fields. It is illegal to add more fields than allocated after this */
        /* Use RemoveAllFields() to free up everything. */

        if (!(s->NodeArray = malloc(n * sizeof(struct Node)))) return FALSE;
        s->FirstFree = 0;
        return TRUE;
}

char *SelectedString(Select *s)
{
/* Returns the selected string */

        return FindIndex((struct List *)&s->SelList, s->SelIndex)->ln_Name;
}

void UpdateString(Select *s, int index, char *newstring)
{
/* Changes a string. */

        if (s->SelWnd)
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach

        FindIndex((struct List *)&s->SelList, index)->ln_Name = newstring;

        if (s->SelWnd)
        GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
}


/* // I comment this to save space
char *AddStringFirst(Select *s, char *str)
{
        struct Node *newnode;

        if (s->NodeArray)       newnode = s->NodeArray[s->FirstFree++];
        else if (!(newnode = (struct Node *)malloc(sizeof(struct Node)))) return str;
        newnode->ln_Name = str;

        if (s->SelWnd)
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach

        AddHead((struct List *)&s->SelList, newnode);
        s->SelTotal++;

        if (s->SelWnd)
        GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);

        return str;
}
*/
char *AddStringLast(Select *s, char *str)
{
        struct Node *newnode;

        if (s->NodeArray)       newnode = &s->NodeArray[s->FirstFree++];
        else if (!(newnode = (struct Node *)malloc(sizeof(struct Node)))) return str;
        newnode->ln_Name = str;

        if (s->SelWnd)
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach

        AddTail((struct List *)&s->SelList, newnode);
        s->SelTotal++;

        if (s->SelWnd)
        GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);

        return str;
}

/* // I comment this to save space
char *AddString(Select *s, char *str, int index)
{
        struct Node *newnode;

        if (s->NodeArray)       newnode = &s->NodeArray[s->FirstFree++];
        else if (!(newnode = (struct Node *)malloc(sizeof(struct Node)))) return str;
        newnode->ln_Name = str;

        if (s->SelWnd)
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach

        if (index == 0) AddHead((struct List *)&s->SelList, newnode);
        else Insert((struct List *)&s->SelList, newnode,
                                         FindIndex((struct List *)&s->SelList, index-1));
        s->SelTotal++;

        if (s->SelWnd)
        GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);

        return str;
}

char *RemoveFirstString(Select *s)
{
        struct Node *old;
        char *oldstr;

        if (!s->SelTotal) return NULL;

        if (s->SelWnd)
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach

        old = RemHead((struct List *)&s->SelList);
        s->SelTotal--;
        if (s->SelIndex == s->SelTotal) s->SelIndex--;

        if (s->SelWnd)
        GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);

        oldstr = old->ln_Name;
        if (!s->NodeArray) free(old);
        return oldstr;
}

char *RemoveLastString(Select *s)
{
        struct Node *old;
        char *oldstr;

        if (!s->SelTotal) return NULL;

        if (s->SelWnd)
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach

        old = RemTail((struct List *)&s->SelList);

        s->SelTotal--;
        if (s->SelIndex == s->SelTotal) s->SelIndex--;

        if (s->SelWnd)
        GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);

        oldstr = old->ln_Name;
        if (!s->NodeArray) free(old);
        return oldstr;
}

char *RemoveString(Select *s, int index)
{
        struct Node *old;
        char *oldstr;

        if (s->SelWnd)
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach

        old = FindIndex((struct List *)&s->SelList, index);
        Remove(old);
        s->SelTotal--;
        if (s->SelIndex == s->SelTotal) s->SelIndex--;

        if (s->SelWnd)
        GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);

        if (old) {
                oldstr = old->ln_Name;
                if (!s->NodeArray) free(old);
                return oldstr;
        }
        return NULL;
}

*/

void RemoveAllStrings(Select *s)
{
        struct Node *old;

        if (s->SelWnd)
                GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, ~0, TAG_END); // Detach

        if (s->NodeArray) {
                free(s->NodeArray);
                s->NodeArray = NULL;
                NewList((struct List *)&s->SelList);
        }
        else while (old = RemTail((struct List *)&s->SelList)) free(old);

        if (s->SelWnd)
        GT_SetGadgetAttrs(s->ListView, s->SelWnd, NULL, GTLV_Labels, &s->SelList, TAG_END);
        s->SelTotal = 0;
}

void DisableSelect(Select *s, BOOL flag) {
                if (s->SelWnd) {
                        GT_SetGadgetAttrs(s->ListView,s->SelWnd,NULL,
                         GA_Disabled, flag, TAG_DONE);
                }
}

void CurrentIndex(Select *s, int index)
{
        if (s) {
                s->SelIndex = index;
                if (s->SelWnd) UpdateListView(s);
        }
}

int HandleSelectIDCMP(Select *s)
{
        struct IntuiMessage     *m;
        int                     (*func)(Select*);
        BOOL                    running = SEL_PRIVATE;

        while( s->SelWnd && (m = GT_GetIMsg( s->SelWnd->UserPort ))) {

                CopyMem(( char * )m, ( char * )&s->SelMsg, (long)sizeof( struct IntuiMessage ));

                GT_ReplyIMsg( m );

                switch ( s->SelMsg.Class ) {

                        case    IDCMP_REFRESHWINDOW:
                                GT_BeginRefresh( s->SelWnd );
                                GT_EndRefresh( s->SelWnd, TRUE );
                                break;

                        case    IDCMP_CLOSEWINDOW:
                                running = SelCloseWindow(s);
                                break;

                        case    IDCMP_NEWSIZE:
                                running = SelNewSize(s);
                                break;

                        case    IDCMP_VANILLAKEY:
                                running = SelVanillaKey(s);
                                break;

                        case    IDCMP_RAWKEY:
                                running = SelRawKey(s);
                                break;

                        case    IDCMP_GADGETUP:
                        case    IDCMP_GADGETDOWN:
                                func = (int(*)(Select*))(( struct Gadget * )s->SelMsg.IAddress )->UserData;
                                if(func)
                                    running = func(s);
                                break;
                }
        }
        return( running );
}

int OpenSelect(Select *s, struct Window *parentwin, char *wintitle, char *screentitle)
{
        char *bufp, *namep;

        if (s->SelWnd) return 5L; /* Already opened */

        if (s->SelWidth == ~0) {        /* Window has never been opened before */
                s->SelWidth = 220;
//              ComputeFont( s->SelWidth, s->SelHeight );
                s->SelWidth = ComputeX( s->SelWidth );
                s->SelHeight = ComputeY( s->SelHeight );
        
                if (parentwin) {
                        s->SelLeft =  parentwin->LeftEdge + parentwin->Width;
                        s->SelTop = parentwin->TopEdge + (parentwin->Height - s->SelHeight)/2;
                }
                if (s->SelLeft + s->SelWidth > Scr->Width)
                        s->SelLeft = parentwin->LeftEdge - s->SelWidth;
        }

        /* Strip underscore _ for cosmethic reasons */
        for (bufp = s->SelWdt, namep = wintitle; *namep; namep++)
                if (*namep != '_') *bufp++ = *namep;
        
    /* Strip trailing ':' if there's any */
        if(*(bufp-1) != ':')
                *bufp = ':';
        else
                *bufp = '\0';

        s->SelCompleteBuf = bufp+1;
        s->SelCompleteBuf[0] = '\0';

        s->SelZoom[0] = s->SelLeft;
        s->SelZoom[1] = 0;
        s->SelZoom[2] = s->SelWidth;
        s->SelZoom[3] = Scr->Height;
        
        if ( ! ( s->SelWnd = OpenWindowTags( NULL,
                                WA_Left,        s->SelLeft,
                                WA_Top,         s->SelTop,
                                WA_Width,       s->SelWidth,
                                WA_Height,      s->SelHeight,
                                WA_IDCMP,       LISTVIEWIDCMP|BUTTONIDCMP|IDCMP_NEWSIZE|IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_VANILLAKEY|IDCMP_REFRESHWINDOW,
                                WA_Flags,       WFLG_SIZEGADGET|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SIZEBBOTTOM|WFLG_SIMPLE_REFRESH|WFLG_ACTIVATE|WFLG_RMBTRAP,
                                WA_Title,       s->SelWdt,
                                WA_ScreenTitle, screentitle,
                                WA_PubScreen,   Scr,
                                WA_MinWidth,    160,
                                WA_MinHeight,   120,
                                WA_MaxWidth,    -1,
                                WA_MaxHeight,   -1,
                                WA_Zoom, s->SelZoom,
                                TAG_DONE )))
        return( 4L );

        MyCreateAllGadgets(s);
        return( 0L );
}

void CloseSelect(Select *s)
{
        if ( s->SelWnd        ) {
                s->SelLeft = s->SelWnd->LeftEdge;
                s->SelTop = s->SelWnd->TopEdge;
                s->SelWidth = s->SelWnd->Width;
                s->SelHeight = s->SelWnd->Height;

                CloseWindow( s->SelWnd );
                s->SelWnd = NULL;
        }

        if ( s->SelGList      ) {
                FreeGadgets( s->SelGList );
                s->SelGList = NULL;
        }
}

Select *NewSelect(void)
{
/* Data för ListView gadget */
        Select *s = (Select*) malloc(sizeof(Select));
        if (!s) return NULL;

        s->SelWnd = NULL;
        s->SelGList = NULL;
        s->ListView = NULL;
        s->SelWidth = ~0; /* (220) Window has never been opened before */
        s->SelHeight = 280;
        s->SelLeft =  (Scr->Width - 220) >> 1;
        s->SelTop = (Scr->Height - s->SelHeight) >> 1;
        s->SelIndex = 0;
        s->SelTotal = 0;
        s->StartSecs = 0, s->StartMicros = 0;
        s->NodeArray = NULL;

        NewList((struct List *)&s->SelList);

        return s;
}

void DeleteSelect(Select *s)
{
        CloseSelect(s);
        RemoveAllStrings(s);
        free(s);
}
