/*
 * MandelVroom 2.0
 *
 * (c) Copyright 1987,1989  Kevin L. Clague, San Jose, CA
 *
 * All rights reserved.
 *
 * Permission is hereby granted to distribute this program's source
 * executable, and documentation for non-comercial purposes, so long as the
 * copyright notices are not removed from the sources, executable or
 * documentation.  This program may not be distributed for a profit without
 * the express written consent of the author Kevin L. Clague.
 *
 * This program is not in the public domain.
 *
 * Fred Fish is expressly granted permission to distribute this program's
 * source and executable as part of the "Fred Fish freely redistributable
 * Amiga software library."
 *
 * Permission is expressly granted for this program and it's source to be
 * distributed as part of the Amicus Amiga software disks, and the
 * First Amiga User Group's Hot Mix disks.
 *
 * contents:  this file contains tools to allocate and free gadgets and
 * gadget imagery for MandelVroom.
 */

#include "mandp.h"

#define TOP 1
#define BOT 2

/*************************************************************************
 *
 * Allocate and ititialize gadget tools
 *
 ************************************************************************/

/*
 * Make a generic boolean gadget
 */
struct Gadget *MakeBool(x,y,xd,yd,c,id, flags)
  SHORT  x,y,xd,yd;
  UBYTE  c;
  USHORT id;
  USHORT flags;
{
  register struct Gadget *NewGadget;
  register struct Image  *NewImage,*ShadowImage;

  NewGadget = (struct Gadget *)
    safeAllocMem( (ULONG) sizeof(struct Gadget), (LONG) MEMF_CLEAR );

  if (NewGadget == NULL) return( NewGadget );

  if ( flags & GADGIMAGE ) {

    NewImage = (struct Image *)
      safeAllocMem( (ULONG) sizeof(struct Image), (LONG) MEMF_CLEAR );

    if ( NewImage == NULL ) {
      FreeMem( (char *) NewGadget, (LONG) sizeof(struct Gadget));
      return( NULL );
    }

    ShadowImage = (struct Image *)
      safeAllocMem( (ULONG) sizeof(struct Image), (LONG) MEMF_CLEAR );

    if ( ShadowImage == NULL ) {
      FreeImage( NewImage );
      FreeMem( (char *) NewGadget, (LONG) sizeof(struct Gadget));
      return( NULL );
    }

    NewImage->Width = xd;
    NewImage->Height = yd;
    NewImage->PlaneOnOff = c;

    ShadowImage->LeftEdge = 1 + XScale;
    ShadowImage->TopEdge = 1 + YScale;
    ShadowImage->Width = xd;
    ShadowImage->Height = yd;
    ShadowImage->PlaneOnOff = SHADOWPEN;
    ShadowImage->NextImage = NewImage;

    NewGadget->GadgetRender = (APTR) ShadowImage;

  } else {

    NewGadget->GadgetRender = (APTR)
                              ShadowBorder( BEVELEDUP, 1, 1, xd-1, yd-1 );
  }

  NewGadget->LeftEdge = x;
  NewGadget->TopEdge  = y;
  NewGadget->Width    = xd;
  NewGadget->Height   = yd;
  NewGadget->Flags    = GADGHCOMP | flags;
  NewGadget->Activation = GADGIMMEDIATE;
  NewGadget->GadgetType = BOOLGADGET;
  NewGadget->GadgetID = id;

  return(NewGadget);
} /* MakeBool */

/*
 * Make a generic potentiometer gadget
 */
struct Gadget *MakePot(x, y, xd, yd, id, cnt)
  SHORT  x,y,xd,yd;
  USHORT id;
  USHORT cnt;
{
  register struct Gadget   *NewGadget;
  register struct Image    *NewImage;
  register struct PropInfo *NewInfo;

  NewGadget = (struct Gadget *)
    safeAllocMem( (ULONG) sizeof(struct Gadget), MEMF_CLEAR );

  if (NewGadget == NULL) goto nogadget;

  NewImage = (struct Image *)
    safeAllocMem( (ULONG) sizeof(struct Image), MEMF_CLEAR );

  if (NewImage == NULL) goto noimage;

  NewInfo = (struct PropInfo *)
    safeAllocMem( (ULONG) sizeof(struct PropInfo), MEMF_CLEAR );

  if (NewInfo == NULL) goto noinfo;

  NewGadget->LeftEdge = x;
  NewGadget->TopEdge  = y;
  NewGadget->Width    = xd;
  NewGadget->Height   = yd;
  NewGadget->Flags    = GADGHIMAGE | GADGIMAGE;
  NewGadget->Activation   = RELVERIFY;
  NewGadget->GadgetType   = PROPGADGET;
  NewGadget->GadgetRender = (APTR) NewImage;
  NewGadget->SpecialInfo  = (APTR) NewInfo;
  NewGadget->GadgetID     = id;

  NewImage->PlaneOnOff = SHADOWPEN;
  NewImage->Width  = 4 << XScale;
  NewImage->Height = 3 << YScale;

  NewInfo->Flags = PROPBORDERLESS | FREEVERT;
  NewInfo->VertBody = 1;

  return(NewGadget);

noinfo:
  FreeMem( (char *) NewImage,  (LONG) sizeof(struct Image));

noimage:
  FreeMem( (char *) NewGadget, (LONG) sizeof(struct Gadget));

nogadget:
  return( NULL );
} /* MakePot */

/*
 * Make a generic string gadget
 */
struct Gadget *MakeString( x, y, length, id, String )
  SHORT  x,y,length;
  USHORT id;
  char *String;
{
  register struct Gadget     *NewGadget;
  register struct StringInfo *NewString;
  register struct Border     *Border;

  register char *NewBuffer;

  NewGadget = (struct Gadget *)
    safeAllocMem( (ULONG) sizeof(struct Gadget), (LONG) MEMF_CLEAR );

  if ( NewGadget == NULL ) goto nogadget;

  NewString = (struct StringInfo *)
    safeAllocMem( (ULONG) sizeof(struct StringInfo), (LONG) MEMF_CLEAR );

  if (NewString == NULL) goto nostring;

  NewBuffer = (char *) safeAllocMem( (ULONG) length + 1, (LONG) MEMF_CLEAR );

  if (NewBuffer == NULL) goto nobuffer;

  Border = ShadowBorder( BEVELEDDOWN, -1, -1, length * 8 + 1, 9 );

  NewGadget->LeftEdge = x;
  NewGadget->TopEdge  = y;
  NewGadget->Width    = length * 8;
  NewGadget->Height   = 8;
  NewGadget->Flags    = GADGHCOMP;
  NewGadget->Activation = STRINGRIGHT;
  NewGadget->GadgetType = STRGADGET;
  NewGadget->GadgetID = id;
  NewGadget->GadgetRender = (APTR) Border;
  NewGadget->SpecialInfo  = (APTR) NewString;

  NewString->MaxChars = length + 1;
  NewString->BufferPos = 0;
  NewString->DispPos = 0;
  NewString->Buffer = (UBYTE *) NewBuffer;

  strcpy( NewBuffer, String );

  return(NewGadget);

nobuffer:

  FreeMem( (char *) NewString, (long) sizeof( struct StringInfo ) );

nostring:

  FreeMem( (char *) NewGadget, (long) sizeof( struct Gadget ) );

nogadget:

  return( NULL );

} /* MakeString */

/*
 * Free a string of gadgets
 */
FreeGadgets(FirstGadget)
  struct Gadget *FirstGadget;
{
  register struct Gadget *NextGadget;
  register struct StringInfo *String;
  register struct Border *Render;

  while (FirstGadget) {

    Render = (struct Border *) FirstGadget->GadgetRender;

    if ( Render ) {
      if (FirstGadget->Flags & GADGIMAGE) {

        FreeImage( (struct Inage *) Render );
      } else {

        FreeBorder( Render );
      }
    }

    Render = (struct Border *) FirstGadget->SelectRender;

    if ( Render ) {
      if (FirstGadget->Flags & GADGIMAGE) {

        FreeImage( (struct Inage *) Render );
      } else {

        FreeBorder( Render );
      }
    }

    if (FirstGadget->SpecialInfo) {

      switch( FirstGadget->GadgetType ) {

        case PROPGADGET:
             FreeMem( (char *) FirstGadget->SpecialInfo,
                      (LONG) sizeof(struct PropInfo));
             break;

        case STRGADGET:
             String = (struct StringInfo *) FirstGadget->SpecialInfo;
             FreeMem( (char *) String->Buffer, (LONG) String->MaxChars );
             FreeMem( (char *) String, (LONG) sizeof(struct StringInfo));

             break;
      }
    }

    FreeIntui( FirstGadget->GadgetText );

    NextGadget = FirstGadget->NextGadget;

    FreeMem( (char *) FirstGadget, (LONG) sizeof(struct Gadget));

    FirstGadget = NextGadget;
  }
} /* FreeGadgets */

FreeImage( Image )
  struct Image *Image;
{
  register struct Image *image, *next;

  next = Image;

  while ( image = next ) {

    next = image->NextImage;

    FreeMem( (char *) image, (LONG) sizeof(struct Image));
  }
}

struct Border *
MakeShadow( pen, numverts )
  LONG pen;
  int numverts;
{
  register struct Border *NewBorder;
  register SHORT *NewCounts;

  NewBorder = (struct Border *)
    safeAllocMem( (ULONG) sizeof(struct Border), (LONG) MEMF_CLEAR );

  if (NewBorder == NULL) return( NULL );

  NewCounts = (SHORT *)
    safeAllocMem( (ULONG) sizeof(SHORT) * 2 * numverts, (LONG) MEMF_CLEAR );

  if (NewCounts == NULL) {
    FreeMem( (char *) NewBorder, (LONG) sizeof(struct Border) );
    return( NULL );
  }

  NewBorder->FrontPen = pen;
  NewBorder->DrawMode = JAM1;
  NewBorder->XY       = NewCounts;
  NewBorder->Count    = numverts;

  return( NewBorder );
}

/*
 * Make an Border structure
 */
static struct Border *
MakeCornerShadow( Type, left, top, Width, Height, pen )

           LONG Type;
  register LONG left,  top;
           LONG Width, Height;
           LONG pen;
{
  register struct Border *NewBorder;
  register SHORT *NewCounts;

  register LONG right = left + Width;
  register LONG bot   = top + Height;
           LONG cornerx;
           LONG cornery;
           LONG direction;

#define NUMVERTS 6

  NewBorder = MakeShadow( pen, NUMVERTS );

  if (NewBorder == NULL) return( NewBorder );

  if ( Type == TOP ) {
    cornerx = left;  cornery = top; direction = -1;
  } else {
    cornerx = right; cornery = bot; direction =  1;
  }

  NewCounts = NewBorder->XY;

  *NewCounts++ = left;    *NewCounts++ = bot;
  *NewCounts++ = cornerx; *NewCounts++ = cornery;
  *NewCounts++ = right;   *NewCounts++ = top;

  left--; top--; bot++; right++;
  cornerx += direction; cornery += direction;

  *NewCounts++ = right;   *NewCounts++ = top;
  *NewCounts++ = cornerx; *NewCounts++ = cornery;
  *NewCounts++ = left;    *NewCounts++ = bot;

  return( NewBorder );
} /* MakeCornerShadow */

struct Border *
ShadowBorder( Type, left, top, xdim, ydim )
  int Type;
  int left, top;
  int xdim, ydim;
{
  register struct Border *Border1, *Border2;
  register int            Pen1,     Pen2;

  if (Type == BEVELEDUP) {
    Pen1 = HIGHLIGHTPEN; Pen2 = SHADOWPEN;
  } else {
    Pen2 = HIGHLIGHTPEN; Pen1 = SHADOWPEN;
  }

  Border1 = MakeCornerShadow( (long) TOP,  (long) left, (long) top,
                              (long) xdim, (long) ydim, (long) Pen1 );

  if ( Border1 ) {

    Border2 = MakeCornerShadow( (long) BOT,  (long) left, (long) top,
                                (long) xdim, (long) ydim, (long) Pen2 );
    Border1->NextBorder = Border2;
  }

  return( Border1 );
}

FreeBorder( Border )
  struct Border *Border;
{
  register struct Border *border, *next;

  next = Border;

  while ( border = next ) {

    next = border->NextBorder;

    FreeMem( (char *) border->XY, (LONG) sizeof(SHORT) * border->Count * 2);
    FreeMem( (char *) border,     (LONG) sizeof(struct Border));
  }
}



/*
 * Make an IntuiText structure
 */
struct IntuiText *MakeIntui(str, x, y, frontpen, backpen, drawmode )
  char *str;
  LONG  x, y;
  LONG  frontpen, backpen;
  LONG  drawmode;
{
  register struct IntuiText *NewIntui;
  register char  *NewString;

  NewIntui = (struct IntuiText *)
    safeAllocMem( (ULONG) sizeof(struct IntuiText), (LONG) MEMF_CLEAR );

  if ( NewIntui == NULL ) return( NULL );

  NewString = (char *)
    safeAllocMem( (ULONG) strlen( str ) + 1, (LONG) MEMF_CLEAR );

  if ( NewString == NULL ) {
    FreeMem( (char *) NewIntui, (long) sizeof(struct IntuiText) );
    return( NULL );
  }

  NewIntui->FrontPen = frontpen;
  NewIntui->BackPen  = backpen;
  NewIntui->DrawMode = drawmode;
  NewIntui->LeftEdge = x;
  NewIntui->TopEdge  = y;
  NewIntui->IText = (UBYTE *) NewString;

  strcpy( NewString, str );

  return(NewIntui);
} /* MakeIntui */

struct IntuiText *
ShadowIntui( str, x, y )
  char *str;
  LONG x,y;
{
  register struct IntuiText *Intui1, *Intui2, *Intui3;

  Intui1 = MakeIntui( str,  x,     y,     NORMALPEN, NORMALPEN, JAM2 );
  Intui2 = MakeIntui( str,  x + 1, y + 1, SHADOWPEN, NORMALPEN, JAM2 );
  Intui3 = MakeIntui( str,  x,     y,     MEDIUMPEN, (long) 0,  JAM1 );

  Intui1->NextText = Intui2;
  Intui2->NextText = Intui3;

  return( Intui1 );
}

FreeIntui( Intui )
  struct IntuiText *Intui;
{
  register struct IntuiText *intui, *next;

  next = Intui;

  while ( intui = next ) {

    next = intui->NextText;

    FreeMem( (char *) intui->IText, (long) strlen((char *)intui->IText) + 1);
    FreeMem( (char *) intui, (LONG) sizeof(struct IntuiText));
  }
}

#if 0
struct Border *
MakeWindowBorder( NewWindow )
  register struct NewWindow *NewWindow;
{
  register struct Border *Border1,*Border2;
  register SHORT  *Verts;
  register SHORT  Bottom, Right;

  Border1 = MakeShadow( HIGHLIGHTPEN, 2 );

  if (Border1 == NULL)
    return NULL;

  Border2 = MakeShadow( SHADOWPEN, 3 );

  if (Border2 == NULL) {
    FreeBorder( Border1 );
    return NULL;
  }

  Bottom = NewWindow->Height - 1;
  Right  = NewWindow->Width  - 1;

  Verts = Border1->XY;

  /* Vertex.X        Vertext.Y */

  *Verts++ = 0;     *Verts++ = TOPMARG;
  *Verts++ = 0;     *Verts++ = Bottom;

  Verts = Border2->XY;

  /* Vertex.X        Vertext.Y */

  *Verts++ = 0;     *Verts++ = Bottom;
  *Verts++ = Right; *Verts++ = Bottom;
  *Verts++ = Right; *Verts++ = TOPMARG - 1;

  Border1->NextBorder = Border2;

  return( Border1 );
}
#endif
