/*
   GDataList.mcc
   Note: Compiled with SAS/C 6.56
*/

/* Includes */
#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/mui.h>
#include <dos/dos.h>
#include <clib/alib_protos.h>
#include <clib/alib_stdio_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/utility_protos.h>
#include <clib/muimaster_protos.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>

#include <pragmas/exec_sysbase_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/muimaster_pragmas.h>

#include <mui/DataList_mcc.h>
#include <mui/GDataList_mcc.h>

//
// CLASS DEFINITIONS FOR MCCHEADER =======================================
//
#define CLASS        MUIC_GDataList
#define SUPERCLASS   MUIC_Group
#define VERSION      1
#define REVISION     1

static const char UserLibID[] = "\0$VER: GDataList.mcc 1.1 (25.5.97)";
//
// CLASS DEFINITIONS FOR MCCHEADER =======================================
//


#define REG(x) register __ ## x
#define ASM    __asm
#define SAVEDS __saveds

LONG __stack = 8192;


struct Data
{
   APTR      group;         // the object tree for this class

   SHORT     sFrameType;    // TRUE = InputListFrame; FALSE = ReadListFrame
   SHORT     sDelVerify;
   LONG      lInsertPosition;
   UBYTE     ubDelimeter;

   Object   *list;
   Object   *newbutton;
   Object   *delbutton;
   Object   *upbutton;
   Object   *downbutton;
   Object   *topbutton;
   Object   *bottombutton;
   Object   *numseltext;
   Object   *pFocusObject;

   UBYTE     szNumSelected[256];

   ULONG    *pulDefaultValues;
   UBYTE    *pszDelButton;
   UBYTE    *pszNewButton;
   UBYTE    *pszUpButton;
   UBYTE    *pszDownButton;
   UBYTE    *pszTopButton;
   UBYTE    *pszBottomButton;
   UBYTE    *pszNumSelected;

   UBYTE    *pszDelConfirm;
   UBYTE    *pszDelResponse;
};

struct Library *GDataListBase = NULL;

struct Library *MUIMasterBase = NULL;
struct Library *UtilityBase   = NULL;
struct Library *IntuitionBase = NULL;
struct Library *SysBase       = NULL;
struct Library *DOSBase       = NULL;

int CXBRK(void) { return(0); }
int _CXBRK(void) { return(0); }
void chkabort(void) {}

#ifndef MAKE_ID
#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
#endif

#include <mui/mccheader.c>


//
//   L  I  S  T     H  O  O  K     F  U  N  C  T  I  O  N  S
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SAVEDS ASM APTR fnNumSelFunc( REG(a0) struct Hook *hook, REG(a1) APTR **args, REG(a2) APTR obj )
{
   struct Data *data = (struct Data *)(*args);
   ULONG        ulNumSel = 0;


   // get number of selected items
   DoMethod( data->list, MUIM_List_Select, MUIV_List_Select_All, MUIV_List_Select_Ask, &ulNumSel );

   //
   // if a "Num Selected" object exists, update it!
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if ( data->pszNumSelected )
   {
      sprintf( data->szNumSelected, data->pszNumSelected, ulNumSel );
      DoMethod( data->numseltext, MUIM_NoNotifySet, MUIA_Text_Contents, data->szNumSelected );
   }
   return(0);
}
static struct Hook hNumSelHook = {
   {NULL, NULL},
   (void *)fnNumSelFunc,
   NULL, NULL
};
SAVEDS ASM APTR fnDoubleClickFunc( REG(a0) struct Hook *hook, REG(a1) APTR **args, REG(a2) APTR obj )
{
   struct Data *data = (struct Data *)(*args);


   DoMethod( _win(obj), MUIM_NoNotifySet, MUIA_Window_ActiveObject, data->pFocusObject );
   return(0);
}
static struct Hook hDoubleClickHook = {
   {NULL, NULL},
   (void *)fnDoubleClickFunc,
   NULL, NULL
};


//
//   H  O  O  K  S
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SAVEDS ASM APTR hNewButton   ( REG(a0) struct Hook *hook, REG(a1) APTR **args, REG(a2) APTR obj )
{
   struct Data *data = (struct Data *)(*args);


   DoMethod( data->list, MUIM_DataList_AddRecordFromArray,
             (ULONG **)(data->pulDefaultValues), MUIV_DataList_AddRecord_ReplaceNone, data->lInsertPosition );
   DoMethod( _win(obj), MUIM_NoNotifySet, MUIA_Window_ActiveObject, data->pFocusObject );
   return( NULL );
}
static struct Hook hNewButtonHook = {
   {NULL, NULL},
   (void *)hNewButton,
   NULL, NULL
};

SAVEDS ASM APTR hDelButton   ( REG(a0) struct Hook *hook, REG(a1) APTR **args, REG(a2) APTR obj )
{
   BOOL         fDeleteIt = FALSE;
   struct Data *data = (struct Data *)(*args);


   switch( data->sDelVerify )
   {
      case FALSE:
         fDeleteIt = TRUE;
         break;
      case TRUE:
         if ( MUI_Request( _app(obj), _win(obj), 0, NULL, data->pszDelResponse,
                           data->pszDelConfirm, NULL ) == 1 )
         {
            fDeleteIt = TRUE;
         }
         break;
   }

   if ( fDeleteIt == TRUE )
   {
      DoMethod( data->list, MUIM_List_Remove, MUIV_List_Remove_Active );
   }

   return( NULL );
}
static struct Hook hDelButtonHook = {
   {NULL, NULL},
   (void *)hDelButton,
   NULL, NULL
};

SAVEDS ASM APTR hUpButton    ( REG(a0) struct Hook *hook, REG(a1) APTR **args, REG(a2) APTR obj )
{
   struct Data *data = (struct Data *)(*args);


   DoMethod( data->list, MUIM_List_Move, MUIV_List_Move_Active, MUIV_List_Move_Previous );
   DoMethod( data->list, MUIM_NoNotifySet, MUIA_List_Active, MUIV_List_Active_Up );
   return(0);
}
static struct Hook hUpButtonHook = {
   {NULL, NULL},
   (void *)hUpButton,
   NULL, NULL
};

SAVEDS ASM APTR hDownButton  ( REG(a0) struct Hook *hook, REG(a1) APTR **args, REG(a2) APTR obj )
{
   struct Data *data = (struct Data *)(*args);


   DoMethod( data->list, MUIM_List_Move, MUIV_List_Move_Active, MUIV_List_Move_Next );
   DoMethod( data->list, MUIM_NoNotifySet, MUIA_List_Active, MUIV_List_Active_Down );
   return(0);
}
static struct Hook hDownButtonHook = {
   {NULL, NULL},
   (void *)hDownButton,
   NULL, NULL
};

SAVEDS ASM APTR hTopButton   ( REG(a0) struct Hook *hook, REG(a1) APTR **args, REG(a2) APTR obj )
{
   struct Data *data = (struct Data *)(*args);


   DoMethod( data->list, MUIM_List_Move, MUIV_List_Move_Active, MUIV_List_Move_Top );
   DoMethod( data->list, MUIM_NoNotifySet, MUIA_List_Active, 0 );
   return(0);
}
static struct Hook hTopButtonHook = {
   {NULL, NULL},
   (void *)hTopButton,
   NULL, NULL
};

SAVEDS ASM APTR hBottomButton( REG(a0) struct Hook *hook, REG(a1) APTR **args, REG(a2) APTR obj )
{
   struct Data *data = (struct Data *)(*args);


   DoMethod( data->list, MUIM_List_Move, MUIV_List_Move_Active, MUIV_List_Move_Bottom );
   DoMethod( data->list, MUIM_NoNotifySet, MUIA_List_Active, MUIV_List_Active_Bottom );
   return(0);
}
static struct Hook hBottomButtonHook = {
   {NULL, NULL},
   (void *)hBottomButton,
   NULL, NULL
};

static ULONG mNew(struct IClass *cl,Object *obj,struct opSet *msg)
{
   struct Data  *data;
   char        **ppszMovers = NULL;
   APTR          pObjNewDel  = NULL, pObjNumSel  = NULL, pObjMovers  = NULL;
   APTR          pLinkNewDel = NULL, pLinkNumSel = NULL, pLinkMovers = NULL;
   ULONG         ulFrameType;
   APTR          pLV = NULL;


   if (!(obj = (Object *)DoSuperMethodA(cl,obj,(Msg)msg)))
      return(0);

   data = INST_DATA(cl,obj);
   memset( (char *)data, 0, sizeof( struct Data ) );
   data->pulDefaultValues = (ULONG *)GetTagData(MUIA_GDataList_DefaultValues , NULL, ((struct opSet *)msg)->ops_AttrList);
   data->pszDelButton     = (UBYTE *)GetTagData(MUIA_GDataList_DelButton     , (ULONG)"_Del", ((struct opSet *)msg)->ops_AttrList);
   data->pszDelConfirm    = (UBYTE *)GetTagData(MUIA_GDataList_DelConfirm    , (ULONG)"Are you sure you want to delete the item(s)?", ((struct opSet *)msg)->ops_AttrList);
   data->pszDelResponse   = (UBYTE *)GetTagData(MUIA_GDataList_DelResponse   , (ULONG)"Yes|*No", ((struct opSet *)msg)->ops_AttrList);
   data->sDelVerify       = (SHORT)  GetTagData(MUIA_GDataList_DelVerify     , FALSE, ((struct opSet *)msg)->ops_AttrList);
   data->sFrameType       = (SHORT)  GetTagData(MUIA_GDataList_Input         , TRUE, ((struct opSet *)msg)->ops_AttrList);
   data->lInsertPosition  = (LONG)   GetTagData(MUIA_GDataList_InsertPosition, MUIV_List_Insert_Active, ((struct opSet *)msg)->ops_AttrList);
   data->pFocusObject     = (APTR)   GetTagData(MUIA_GDataList_FocusObject   , NULL, ((struct opSet *)msg)->ops_AttrList);

   ppszMovers = (UBYTE **)GetTagData(MUIA_GDataList_MoveButtons, NULL , ((struct opSet *)msg)->ops_AttrList);
   if ( (LONG)ppszMovers == MUIV_GDataList_MoveButtons_Default )
   {
      data->pszUpButton     = "_Up";
      data->pszDownButton   = "_Down";
      data->pszTopButton    = "_Top";
      data->pszBottomButton = "_Bottom";
   }
   else if ( ppszMovers )
   {
      data->pszUpButton     = *(ppszMovers + 0);
      data->pszDownButton   = *(ppszMovers + 1);
      data->pszTopButton    = *(ppszMovers + 2);
      data->pszBottomButton = *(ppszMovers + 3);
   }

   data->pszNewButton    = (UBYTE *) GetTagData(MUIA_GDataList_NewButton    , (ULONG)"_New", ((struct opSet *)msg)->ops_AttrList);
   data->pszNumSelected  = (UBYTE *) GetTagData(MUIA_GDataList_NumSelected  , NULL, ((struct opSet *)msg)->ops_AttrList);

   ulFrameType = ( data->sFrameType ? MUIV_Frame_InputList : MUIV_Frame_ReadList );

   data->group = HGroup,
      Child, VGroup, GroupSpacing(0),
         Child, pLV = ListviewObject,
            MUIA_Listview_MultiSelect, MUIV_Listview_MultiSelect_Default,
            MUIA_Listview_Input, data->sFrameType,
            MUIA_Listview_List, data->list = DataListObject,
               MUIA_Frame, ( ( data->sFrameType == TRUE ) ? MUIV_Frame_InputList : MUIV_Frame_ReadList ),
               TAG_MORE, msg->ops_AttrList,
               End,
            End,
         Child, pLinkNewDel = HGroup,
            End,
         End,
      Child, pLinkMovers = VGroup,
         End,
      End;

   //
   // Add New and Delete buttons?
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if ( data->sFrameType )
   {
      pObjNewDel =
         HGroup,
            Child, data->newbutton = MUI_MakeObject( MUIO_Button, data->pszNewButton ),
            Child, data->delbutton = MUI_MakeObject( MUIO_Button, data->pszDelButton ),
            Child, HSpace(0),
            Child, pLinkNumSel = HGroup,
               End,
            End;
   }
   else
   {
      /* no New/Del for ReadList */
      pObjNewDel = HSpace(0);
   }

   //
   // Add Items-selected text object?
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if ( data->pszNumSelected )
   {
      pObjNumSel = data->numseltext = TextObject, End;
   }
   else
   {
      /* no seltext object */
      pObjNumSel = HSpace(0);
   }

   //
   // Add movement (up, down, top, bottom) buttons?
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if ( ppszMovers )
   {
      pObjMovers =
         VGroup, MUIA_Group_SameWidth, TRUE, MUIA_HorizWeight, 0,
            Child, data->upbutton     = MUI_MakeObject( MUIO_Button, data->pszUpButton ),
            Child, data->downbutton   = MUI_MakeObject( MUIO_Button, data->pszDownButton ),
            Child, data->topbutton    = MUI_MakeObject( MUIO_Button, data->pszTopButton ),
            Child, data->bottombutton = MUI_MakeObject( MUIO_Button, data->pszBottomButton ),
            Child, VSpace(0),
            End;
   }
   else
   {
      /* no Movement buttons */
      pObjMovers = VSpace(0);
   }

   //
   // Did everything get constructed?  If not, dispose and return 0
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if ( !pObjNewDel || !pObjNumSel || !pObjMovers )
   {
      if ( pObjNewDel )    MUI_DisposeObject( pObjNewDel );
      if ( pObjNumSel )    MUI_DisposeObject( pObjNumSel );
      if ( pObjMovers )    MUI_DisposeObject( pObjMovers );
      CoerceMethod(cl,obj,OM_DISPOSE);
      return(0);
   }
   else
   {
      //
      // Attach child groups to parent
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      DoMethod( pLinkNumSel, OM_ADDMEMBER, pObjNumSel );
      DoMethod( pLinkNewDel, OM_ADDMEMBER, pObjNewDel );
      DoMethod( pLinkMovers, OM_ADDMEMBER, pObjMovers );
      if (!data->group)
      {
         CoerceMethod(cl,obj,OM_DISPOSE);
         return(0);
      }
   }

   if ( data->pszNumSelected )
   {
      sprintf( data->szNumSelected, data->pszNumSelected, 0 );
      set( data->numseltext, MUIA_Text_Contents, data->szNumSelected );
   }

   // add object
   DoMethod( obj, OM_ADDMEMBER, data->group );

   msg->MethodID = OM_SET;    /* a little trick to parse taglist */
   DoMethodA( obj, (Msg)msg );     /* and set attributes with OM_SET. */
   msg->MethodID = OM_NEW;    /* restore method id               */

   // set up interconnections and hooks
   DoMethod( data->newbutton   , MUIM_Notify, MUIA_Pressed, FALSE,
             data->newbutton   , 3, MUIM_CallHook, &hNewButtonHook, data );
   DoMethod( data->delbutton   , MUIM_Notify, MUIA_Pressed, FALSE,
             data->delbutton   , 3, MUIM_CallHook, &hDelButtonHook, data );
   DoMethod( data->upbutton    , MUIM_Notify, MUIA_Pressed, FALSE,
             data->upbutton    , 3, MUIM_CallHook, &hUpButtonHook, data );
   DoMethod( data->downbutton  , MUIM_Notify, MUIA_Pressed, FALSE,
             data->downbutton  , 3, MUIM_CallHook, &hDownButtonHook, data );
   DoMethod( data->topbutton   , MUIM_Notify, MUIA_Pressed, FALSE,
             data->topbutton   , 3, MUIM_CallHook, &hTopButtonHook, data );
   DoMethod( data->bottombutton, MUIM_Notify, MUIA_Pressed, FALSE,
             data->bottombutton, 3, MUIM_CallHook, &hBottomButtonHook, data );

   DoMethod( pLV       , MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
             pLV       , 3, MUIM_CallHook, &hDoubleClickHook, data );
   DoMethod( pLV       , MUIM_Notify, MUIA_Listview_SelectChange, TRUE,
             pLV       , 3, MUIM_CallHook, &hNumSelHook, data );
   DoMethod( data->list, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
             data->list, 3, MUIM_CallHook, &hNumSelHook, data );

   return((ULONG)obj);
}


static ULONG mSet(struct IClass *cl,Object *obj,struct opSet *msg)
{
   struct Data    *data = INST_DATA(cl,obj);
   struct TagItem *tags, *tag;


   for (tags=msg->ops_AttrList;tag=NextTagItem(&tags);)
   {
      switch (tag->ti_Tag)
      {
         case MUIA_GDataList_DelConfirm:
            data->pszDelConfirm = (UBYTE *)GetTagData(MUIA_GDataList_DelConfirm, (ULONG)"Are you sure you want to delete the item(s)?",
                                                     ((struct opSet *)msg)->ops_AttrList);
            break;
         case MUIA_GDataList_DelResponse:
            data->pszDelResponse = (UBYTE *)GetTagData(MUIA_GDataList_DelResponse, (ULONG)"Yes|*No", ((struct opSet *)msg)->ops_AttrList);
            break;
         case MUIA_GDataList_DelVerify:
            data->sDelVerify = (SHORT)GetTagData(MUIA_GDataList_DelVerify, FALSE, ((struct opSet *)msg)->ops_AttrList);
            break;
         case MUIA_GDataList_FocusObject:
            data->pFocusObject = (APTR)GetTagData(MUIA_GDataList_FocusObject, NULL, ((struct opSet *)msg)->ops_AttrList);
            break;

         //
         // Pass these attributes thru to underlying DataList so user
         // can send the group messages as if it were a DataList...
         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         case MUIA_DataList_AttachCount    :
         case MUIA_DataList_Delimeter      :
         case MUIA_DataList_DiskTitles     :
         case MUIA_DataList_MaxRecordLength:
         case MUIA_DataList_Sort           :
         case MUIA_DataList_SortPrimary    :
         case MUIA_DataList_SortSecondary  :
         case MUIA_DataList_Titles         :
            DoMethodA( data->list, (Msg)msg );
            break;
      }
   }

   return(DoSuperMethodA(cl,obj,(Msg)msg));
}


static ULONG mGet(struct IClass *cl,Object *obj,Msg msg)
{
   struct Data *data = INST_DATA(cl,obj);
   ULONG       *store = ((struct opGet *)msg)->opg_Storage;


   switch (((struct opGet *)msg)->opg_AttrID)
   {
      case MUIA_Version              :  *store = VERSION;          return( TRUE );
      case MUIA_Revision             :  *store = REVISION;         return( TRUE );

      case MUIA_GDataList_DelConfirm :  *store = (ULONG)( data->pszDelConfirm  ); return( TRUE );
      case MUIA_GDataList_DelResponse:  *store = (ULONG)( data->pszDelResponse ); return( TRUE );
      case MUIA_GDataList_DelVerify  :  *store = (ULONG)( data->sDelVerify     ); return( TRUE );
      case MUIA_GDataList_FocusObject:  *store = (ULONG)( data->pFocusObject   ); return( TRUE );

      //
      // Pass these attributes thru to underlying DataList so user
      // can send the group messages as if it were a DataList...
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      case MUIA_DataList_AttachCount    :
      case MUIA_DataList_Delimeter      :
      case MUIA_DataList_DiskTitles     :
      case MUIA_DataList_MaxRecordLength:
      case MUIA_DataList_Sort           :
      case MUIA_DataList_SortPrimary    :
      case MUIA_DataList_SortSecondary  :
      case MUIA_DataList_Titles         :
         return( DoMethodA( data->list, (Msg)msg ) );
         break;
   }

   return(DoSuperMethodA(cl,obj,(Msg)msg));
}


ULONG __asm Dispatcher(register __a0 struct IClass *cl,register __a2 Object *obj,register __a1 Msg msg)
{
   struct Data  *data = INST_DATA(cl,obj);


   switch (msg->MethodID)
   {
      case OM_NEW: return(mNew(cl,obj,(APTR)msg));
      case OM_GET: return(mGet(cl,obj,(APTR)msg));
      case OM_SET: return(mSet(cl,obj,(APTR)msg));

      //
      // Pass these methods thru to underlying DataList so user
      // can send the group messages as if it were a DataList...
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      case MUIM_DataList_AddRecord:
      case MUIM_DataList_AddRecordFromArray:
      case MUIM_DataList_Attach:
      case MUIM_DataList_Load:
      case MUIM_DataList_GetRecordArray:
      case MUIM_DataList_Save:
      case MUIM_DataList_Search:
         return( DoMethodA( data->list, msg ) );
   }

   return(DoSuperMethodA(cl,obj,msg));
}
