                                LISTING 3

           StrReq.c Program Including StringsRequest Function


/**************************************************************************
*                                                                         *
*    StrReq.c -- (C) Copyright 1988, by Randy Finch                       *
*                                                                         *
*    This program may be FREELY DISTRIBUTED as long as this copyright     *
*    notice remains intact.  It is NOT PUBLIC DOMAIN.  This code cannot   *
*    be sold without the permission of Randy Finch.                       *
*                                                                         *
*    The function StringsRequest will create a requester with a user      *
*    specified number of string gadgets.                                  *
*                                                                         *
**************************************************************************/


/*-------------------  INCLUDE FILES  ----------------------*/

#include <exec/types.h>
#include <clib/macros.h>
#include <exec/memory.h>
#include <intuition/intuition.h>


/*--------------------  DEFINES  ---------------------*/

#define OKGADGET       1
#define CANCELGADGET   2
#define LEFTMARGIN     10
#define RIGHTMARGIN    10
#define SPACER         5
#define CHARWIDTH      8
#define TOPMARGIN      15
#define BOTTOMMARGIN   15
#define PIXPERENTRY    15
#define MINSRWIDTH     130


/*----------------  GLOBAL VARIABLES  ----------------*/

struct Remember  *RememIntuiText = NULL;
struct Remember  *RememStringInfo = NULL;
struct Remember  *RememGadget = NULL;
struct Remember  *RememRequester = NULL;
struct Remember  *RememStringBuffer = NULL;
struct Remember  *RememUndoBuffer = NULL;


/*-----------------  ExitSR Function  ------------------*/

void ExitSR()
{
  if (RememIntuiText) FreeRemember(&RememIntuiText,TRUE);
  if (RememStringInfo) FreeRemember(&RememStringInfo,TRUE);
  if (RememGadget) FreeRemember(&RememGadget,TRUE);
  if (RememStringBuffer) FreeRemember(&RememStringBuffer,TRUE);
  if (RememUndoBuffer) FreeRemember(&RememUndoBuffer,TRUE);
  if (RememRequester) FreeRemember(&RememRequester,TRUE);
} /* ExitSR */


/*-----------------  MaxInArray Function  ---------------*/

WORD MaxInArray(num, array)
  UBYTE  num;
  WORD   array[];
{
  UBYTE i;
  WORD  max;

  max = MAX(array[0], array[1]);

  for (i = 2; i < num; ++i)
     max = MAX(array[i], max);

  return(max);
} /* MaxInarray */


/*--------------------  MaxStrLenInArray  -----------------*/

WORD MaxStrLenInArray(num, strings)
  UBYTE  num;
  STRPTR strings[];
{
  UBYTE i;
  WORD  max;

  max = MAX(strlen(strings[0]),strlen(strings[1]));

  for (i = 2; i < num; ++i)
     max = MAX(strlen(strings[i]),max);

  return(max);
} /* MaxStrLenInArray */


/*----------------  StringsRequest FUNCTION  ------------------------*/

BOOL StringsRequest(HeaderText, NumEntrys, BoxWidth, Titles, DefText, MaxLenDefText, TypeDefText, window)
  STRPTR HeaderText;
  UBYTE  NumEntrys;
  WORD   BoxWidth[];
  STRPTR Titles[];
  STRPTR DefText[];
  WORD   MaxLenDefText[];
  WORD   TypeDefText[];
  struct Window *window;
{

  /*  Local variables  */

  WORD   WidestBox;
  WORD   WidestTitle;
  WORD   WidestText;
  WORD   WidestEntry;
  WORD   SRWidth;
  WORD   SRHeight;
  UBYTE  i;
  STRPTR CurStrBufPointer;
  STRPTR UndoBufPointer;
  ULONG  class;
  ULONG  choice;

  struct   Remember *StrBufPointer;
  struct   Remember *ITextPointer;
  struct   Remember *SInfoPointer;
  struct   Remember *GPointer;
  struct   Requester *ReqPointer;
  struct   IntuiText *CurITextPointer;
  struct   StringInfo *CurSInfoPointer;
  struct   Gadget *CurGPointer;
  struct   Gadget *LastGPointer;
  struct   IntuiMessage *message;
  struct   Gadget *gadget;

  /*  Text Attribute  */

  static struct TextAttr plain8 = {
     (STRPTR) "topaz.font", 8, FS_NORMAL, FPF_ROMFONT
  };

  /*  Header Text  */

  static struct IntuiText HeaderIText = {
     2, 1, JAM2,
     4, 3,
     &plain8,
     NULL,
     NULL
  };

  /*  OK Gadget  */

  static SHORT OKPoints[] = {
     -3,10,
     -3,-2,
     51,-2,
     51,10,
     -3,10,
     -2,11,
     52,11,
     52,-1
  };

  static struct Border OKBorder = {
     0,0,
     0,1,JAM1,
     8,
     &OKPoints[0],
     NULL
  };

  static struct IntuiText OKText = {
     0,1,JAM2,
     0,0,
     &plain8,
     "  OK  ",
     NULL
  };

  static struct Gadget OKGadget = {
     NULL,
     10,-14,
     48,8,
     GADGHCOMP | GRELBOTTOM,
     GADGIMMEDIATE | ENDGADGET,
     BOOLGADGET | REQGADGET,
     (APTR) &OKBorder,
     NULL,
     &OKText,
     0,
     NULL,
     OKGADGET,
     NULL
  };

  /*  Cancel Gadget  */

  static struct IntuiText CancelTxt = {
     0,1,JAM2,
     0,0,
     &plain8,
     "CANCEL",
     NULL
  };

  static struct Gadget CancelGadg = {
     &OKGadget,
     -58,-14,
     48,8,
     GADGHCOMP | GRELBOTTOM | GRELRIGHT,
     GADGIMMEDIATE | ENDGADGET,
     BOOLGADGET | REQGADGET,
     (APTR) &OKBorder,
     NULL,
     &CancelTxt,
     0,
     NULL,
     CANCELGADGET,
     NULL
  };

  static WORD SRPoints[] = {
     2, 1,
     128, 1,
     128, 29,
     2, 29,
     2, 1,
     2, 12,
     128, 12,
     128, 17,
     2, 17
  };

  static struct Border SRBorder = {
     0, 0,
     0, 1, JAM1,
     9,
     &SRPoints[0],
     NULL
  };


  /*-------------  Body of Function  --------------*/

  /*  Initialize some variables  */

  HeaderIText.IText = HeaderText;

  WidestText = MaxInArray(NumEntrys, MaxLenDefText);
  WidestBox  = MaxInArray(NumEntrys, BoxWidth);
  WidestEntry = MIN(WidestText, WidestBox);
  WidestTitle = MaxStrLenInArray(NumEntrys, Titles);

  SRWidth = LEFTMARGIN + RIGHTMARGIN + SPACER + (WidestEntry + WidestTitle) * CHARWIDTH;
  SRWidth = MAX(SRWidth, MINSRWIDTH);
  SRHeight = TOPMARGIN + BOTTOMMARGIN + NumEntrys * PIXPERENTRY;

  /*  Set up Border structure points to match size of requester  */

  SRPoints[2] = SRPoints[4] = SRPoints[12] = SRPoints[14] = SRWidth - 3;
  SRPoints[5] = SRPoints[7] = SRHeight - 2;
  SRPoints[15] = SRPoints[17] = SRHeight - 20;

  /*  Allocate memory for all IntuiText, StringInfo, Gadget, Requester,
      StrBuf, and UndoBuf structures                                    */

  for (i = 0; i < NumEntrys; ++i) {

     if ( ! AllocRemember(&RememIntuiText, sizeof(struct IntuiText), MEMF_CLEAR) ||
          ! AllocRemember(&RememStringInfo, sizeof(struct StringInfo), MEMF_CLEAR) ||
          ! AllocRemember(&RememGadget, sizeof(struct Gadget), MEMF_CLEAR) ||
          ! AllocRemember(&RememStringBuffer, WidestText + 1, MEMF_CLEAR) )

        {
        ExitSR();
        return(FALSE);
        }
  }


  if ( ! AllocRemember(&RememRequester, sizeof(struct Requester), MEMF_CLEAR) ||
       ! AllocRemember(&RememUndoBuffer, WidestText + 1, MEMF_CLEAR) )
     {
     ExitSR();
     return(FALSE);
     }

  ReqPointer = (struct Requester *) RememRequester->Memory;
  UndoBufPointer = (STRPTR) RememUndoBuffer->Memory;

  /*  Initialize IntuiText structures  */

  ITextPointer = RememIntuiText;

  for (i = 0; i < NumEntrys; ++i) {
     CurITextPointer = (struct IntuiText *) ITextPointer->Memory;

     CurITextPointer->FrontPen  = 0;
     CurITextPointer->BackPen   = 1;
     CurITextPointer->DrawMode  = JAM2;
     CurITextPointer->LeftEdge  = -strlen(Titles[i]) * CHARWIDTH - SPACER;
     CurITextPointer->TopEdge   = 0;
     CurITextPointer->ITextFont = &plain8;
     CurITextPointer->IText     = Titles[i];
     CurITextPointer->NextText  = NULL;

     ITextPointer = ITextPointer->NextRemember;

  }


  /*  Initialize StringInfo structures  */

  SInfoPointer = RememStringInfo;
  StrBufPointer = RememStringBuffer;

  for (i = 0; i < NumEntrys; ++i) {
     CurSInfoPointer = (struct StringInfo *) SInfoPointer->Memory;
     CurStrBufPointer = (STRPTR) StrBufPointer->Memory;

     CurSInfoPointer->Buffer     = CurStrBufPointer;
     CurSInfoPointer->UndoBuffer = UndoBufPointer;
     CurSInfoPointer->BufferPos  = 0;
     CurSInfoPointer->MaxChars   = MaxLenDefText[i];
     CurSInfoPointer->DispPos    = 0;

     /*  Other items maintained by Intuition  */

     strcpy(CurStrBufPointer, DefText[i]);

     SInfoPointer = SInfoPointer->NextRemember;
     StrBufPointer = StrBufPointer->NextRemember;

  }

  /*  Initialize Gadgets  */

  LastGPointer = NULL;
  GPointer = RememGadget;
  ITextPointer = RememIntuiText;
  SInfoPointer = RememStringInfo;

  for (i = 0; i < NumEntrys; ++i) {
     CurGPointer = (struct Gadget *) GPointer->Memory;
     CurITextPointer = (struct IntuiText *) ITextPointer->Memory;
     CurSInfoPointer = (struct StringInfo *) SInfoPointer->Memory;

     CurGPointer->NextGadget    = LastGPointer;
     CurGPointer->LeftEdge      = -RIGHTMARGIN - WidestEntry * CHARWIDTH;
     CurGPointer->TopEdge       = TOPMARGIN + i * PIXPERENTRY;
     CurGPointer->Width         = BoxWidth[i] * CHARWIDTH;
     CurGPointer->Height        = 8;
     CurGPointer->Flags         = GADGHCOMP | GRELRIGHT;
     CurGPointer->Activation    = TypeDefText[i];
     CurGPointer->GadgetType    = STRGADGET | REQGADGET;
     CurGPointer->GadgetRender  = NULL;
     CurGPointer->SelectRender  = NULL;
     CurGPointer->GadgetText    = CurITextPointer;
     CurGPointer->MutualExclude = 0;
     CurGPointer->SpecialInfo   = (APTR) CurSInfoPointer;
     CurGPointer->GadgetID      = NULL;
     CurGPointer->UserData      = NULL;

     LastGPointer = CurGPointer;
     GPointer = GPointer->NextRemember;
     ITextPointer = ITextPointer->NextRemember;
     SInfoPointer = SInfoPointer->NextRemember;

  }


  /*  Set OKGadget NextGadget Pointer  */

  OKGadget.NextGadget = LastGPointer;


  /*  Center Header Text  */

  HeaderIText.LeftEdge = (SRWidth-IntuiTextLength(&HeaderIText))/2;


  /*  Initialize Requester  */

  InitRequester(ReqPointer);

  ReqPointer->LeftEdge  = 10;
  ReqPointer->TopEdge   = 12;
  ReqPointer->Width     = SRWidth;
  ReqPointer->Height    = SRHeight;
  ReqPointer->ReqGadget = &CancelGadg;
  ReqPointer->ReqText   = &HeaderIText;
  ReqPointer->BackFill  = 1;
  ReqPointer->Flags     = 0;
  ReqPointer->ReqBorder = &SRBorder;

  if ( ! Request(ReqPointer, window)) {
     ExitSR();
     return(FALSE);
  }

  RefreshGadgets(&CancelGadg, window, ReqPointer);


  /*  Wait for Intuimessage  */

  class = GADGETDOWN;
  choice = CANCELGADGET;

  while (class != REQCLEAR)
    {
    if ((message = (struct IntuiMessage *) GetMsg(window->UserPort)) == 0L)
      {
      Wait(1L << window->UserPort->mp_SigBit);
      continue;
      }
    class  = message->Class;
    gadget = (struct Gadget *) message->IAddress;
    ReplyMsg(message);
    if (class == GADGETDOWN)
      choice = gadget->GadgetID;
    }


  /*  Handle OK and CANCEL  */

  if (choice == OKGADGET) {
     SInfoPointer = RememStringInfo;

     for (i = 0; i < NumEntrys; ++i) {
        CurSInfoPointer = (struct StringInfo *) SInfoPointer->Memory;
        strcpy(DefText[i], CurSInfoPointer->Buffer);
        SInfoPointer = SInfoPointer->NextRemember;
     }

  }

  ExitSR();
  return(TRUE);
}  /* StringsRequester */

