/*
 * 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 the code to open and close the contour
 * palette tool.  It also contains the code that implements the contour
 * commands.
 */

#include "mandp.h"

UBYTE ContOpen;

struct Window *ContWind;

BYTE ContTitle[80];

struct NewWindow NewCont = {
   0,200-80,                 /* start position           */
   320,200,                  /* width, height            */
   (UBYTE) 0, (UBYTE) -1,   /* detail pen, block pen    */
   NULL,                     /* IDCMP flags */
                             /* MandWind flags */
   WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH | NOCAREREFRESH | SMART_REFRESH |
   REPORTMOUSE,
   (struct Gadget *) NULL,   /* first gadget             */
   (struct Image *) NULL,    /* user checkmark           */
   (UBYTE *) NULL,           /* window title             */
   (struct Screen *) NULL,   /* pointer to screen        */
   (struct BitMap *) NULL,   /* pointer to superbitmap   */
   80,80,320,200,            /* sizing                   */
   CUSTOMSCREEN              /* type of screen           */
   };


SHORT Ceiling = 1023;

SHORT  NumContours = NUMCONTS;
SHORT  FirstContour = 0;
SHORT  SaveFirstCont = 0;

int    CurContour;

struct Gadget *ContGadget[DISPCONTS];
struct Gadget *SelGadget[DISPCONTS];

UBYTE  Pattern[NUMCONTS+4];
SHORT  PattSize;

static struct Gadget *ModGadget;

int    BarHotSpot;

LONG BarTop;
LONG BarBot;
LONG BarLeft;
LONG BarRight;
LONG BarWidth;
LONG BarBoxTop;
LONG BarBoxBot;

int ScaledFirst;

struct ContHoriz {
  int CmdLeft;
  int BarLeft;
  int BarWidth;
  int PenLeft;
  int PenWidth;
};

struct ContVert {
  int CmdTop;
  int BarTop;
  int BarHeight;
  int PenTop;
  int PenHeight;
};

static struct ContHoriz  Horiz_I     = {  3,   8,  262,   8, 6*33 };
static struct ContHoriz  Horiz_II    = {  3,   8,  524,   8,12*32 + 4};
static struct ContVert   Verticle_I  = { 11,   31,  10,  47, 42   };
static struct ContVert   Verticle_II = { 11,   31,  14,  52, 82  };

static struct ContHoriz *CurH = &Horiz_I;
static struct ContVert  *CurV = &Verticle_I;


/*
 * Contour related commands
 */

/* Paint Command */

PaintCmd(Msg)
  struct IntuiMessage *Msg;
{
  ReColor( CurPict );
  DisplayBeep(screen);

  if ( CurPict->DrawPict ) {
    ZoomBox( CurPict );
  }
}

SelContCmd(Msg)
  struct IntuiMessage *Msg;
{
  struct Gadget *gadget;

  gadget = (struct Gadget *) Msg->IAddress;

  SetCurCont(GADG_NUM(gadget->GadgetID));
}

SetHeightCmd(Msg)
  struct IntuiMessage *Msg;
{
  struct Window *Window;
  static struct Gadget *gadget;
  struct PropInfo *propinfo;
  static int knobhit;

  Window = Msg->IDCMPWindow;

  switch( Msg->Class ) {

    case GADGETDOWN:
         gadget = (struct Gadget *) Msg->IAddress;
         propinfo = (struct PropInfo *) gadget->SpecialInfo;

         if (knobhit = propinfo->Flags & KNOBHIT) {
           ModifyIDCMP(Window, Window->IDCMPFlags | MOUSEMOVE);
           State  = SETHEIGHTSTATE;
         } else {
           SetContourHeight(gadget);
         }
         break;

    case MOUSEMOVE:
         SetContourHeight(gadget);                         /* potentio */
         break;

    case GADGETUP:
         if (knobhit) {
           ModifyIDCMP(Window, Window->IDCMPFlags & ~MOUSEMOVE);
           ModAll();
         } else {
           SetContourHeight(gadget);                         /* potentio */
           ShowValid();
         }
         State = IDLESTATE;
         break;
  }
}

SetContCmd(Msg)  /* user can set height or pen */
  struct IntuiMessage *Msg;
{
  struct Window  *Window;
  struct Gadget  *gadget;
  struct Picture *Pict;

  Window = Msg->IDCMPWindow;
  gadget = (struct Gadget *) Msg->IAddress;

  switch( Msg->Class ) {

    case GADGETDOWN:
         switch( WIND_TYPE(gadget->GadgetID) ) {

           case CONTYPE:
                if (gadget->GadgetID == CONTSET) {

                  SetToPointer();
                  State = SETCONTSTATE;
                }
                break;

           case PALTYPE:
                if (GADG_TYPE(gadget->GadgetID) == PALPENS) {

                  State = IDLESTATE;
                  SetContourPen( GADG_NUM(gadget->GadgetID) );
                }
                break;
         }
         break;

    case MOUSEBUTTONS:             /* selecting height from the picture */

         if (Msg->Code == SELECTDOWN) {
           Pict = (struct Picture *) Window->UserData;
           if ( Pict ) {
             State = IDLESTATE;
             DoWindowPick(Pict,MouseX,MouseY);
           }
         }
         break;
  }
}

SmoothContCmd(Msg)  /* Smooth heights between two pens */
  struct IntuiMessage *Msg;
{
  struct Gadget  *gadget;
  int    t;

  /* Need contour selection to complete */

  gadget = (struct Gadget *) Msg->IAddress;

  if (Msg->Class == GADGETDOWN) {

    if (gadget->GadgetID == CONTSMTH) { /* Smooth command gadget */

      SetToPointer();
      State = SMOOTHCONTSTATE;
    } else {

      t = GADG_TYPE(gadget->GadgetID);

      if (t == CONTSELS || t == CONTPOTS) {

        t = GADG_NUM(gadget->GadgetID);

        /* smooth to last does decrement by one */

        if (t == CONTLAST)
          *(CurPict->Heights + t) = 0x7fff;

        SmoothContours(CurContour, t);
        State = IDLESTATE;
      }
    }
  }
}

CutContCmd(Msg)  /* Cut Pens between two contours */
  struct IntuiMessage *Msg;
{
  struct Gadget  *gadget;
  int    t;

  /* Need contour selection to complete */

  gadget = (struct Gadget *) Msg->IAddress;

  if (Msg->Class == GADGETDOWN) {

    if (gadget->GadgetID == CONTCUT) { /* Cut command gadget */

      SetToPointer();
      State = CUTCONTSTATE;
    } else {

      t = GADG_TYPE(gadget->GadgetID);

      if (t == CONTSELS || t == CONTPOTS) {

        t = GADG_NUM(gadget->GadgetID);

        CopyPattern(   CurContour, t);
        DeleteContours(CurContour, t);
        State = IDLESTATE;
      }
    }
  }
}

CopyContCmd(Msg)  /* Copy Pens between two contours */
  struct IntuiMessage *Msg;
{
  struct Gadget  *gadget;
  int    t;

  /* Need contour selection to complete */

  gadget = (struct Gadget *) Msg->IAddress;

  if (Msg->Class == GADGETDOWN)  {
    if (WIND_TYPE(gadget->GadgetID) == CONTYPE) {

      if (gadget->GadgetID == CONTCOPY) { /* Copy command gadget */

        SetToPointer();
        State = COPYCONTSTATE;
      } else {

        t = GADG_TYPE(gadget->GadgetID);

        if (t == CONTSELS || t == CONTPOTS) {

          CopyPattern( CurContour, GADG_NUM(gadget->GadgetID));
          State = IDLESTATE;
        }
      }
    } else
    if (WIND_TYPE(gadget->GadgetID) == PALTYPE) {
      SetPenPattern(CurPen, GADG_NUM(gadget->GadgetID));
      State = IDLESTATE;
    }
  }
}

PasteContCmd(Msg)  /* Paste pens into contours */
  struct IntuiMessage *Msg;
{
  struct Gadget  *gadget;
  int    t;

  /* Need contour selection to complete */

  gadget = (struct Gadget *) Msg->IAddress;

  if (Msg->Class == GADGETDOWN) {

    if (gadget->GadgetID == CONTPASTE) { /* Paste command gadget */

      SetToPointer();
      State = PASTECONTSTATE;
    } else {

      t = GADG_TYPE(gadget->GadgetID);

      if (t == CONTSELS || t == CONTPOTS) {

        PastePattern( CurContour, GADG_NUM(gadget->GadgetID));
        State = IDLESTATE;
      }
    }
  }
}

CeilingCmd(Msg)  /* Respond to ceiling gadget */
  struct IntuiMessage *Msg;
{
  struct Gadget  *gadget;
  struct PropInfo *PropInfo;
  ULONG  VertPot;

  extern SHORT    Ceiling;

  if ( Msg->Class == GADGETUP ) {

    /* Need gadget up to complete */

    gadget = (struct Gadget *) Msg->IAddress;
    PropInfo = (struct PropInfo *) gadget->SpecialInfo;

    VertPot  = PropInfo->VertPot;
    VertPot ^= 0xffff;
    VertPot += 1;
    Ceiling = VertPot * CurPict->MaxIteration >> 16;

    ModAll();
    State = IDLESTATE;
  }
}

SlideBarCmd(Msg)
  struct IntuiMessage *Msg;
{
  struct Window *Window;
  static SavedState;

  Window = Msg->IDCMPWindow;                  /* had better be ContWind */

  switch( Msg->Class ) {

    case MOUSEBUTTONS:                        /* slide is starting */
         switch( Msg->Code ) {

           case SELECTDOWN:                   /* ImmediateCmd() filters */
                if (InBarBox()) {
                  StartBarDrag();
                  ModifyIDCMP(Window, Window->IDCMPFlags | MOUSEMOVE);
                  SavedState = State;
                  State = SLIDEBARSTATE;
                }
                break;

           case SELECTUP:                     /* slide is stoping */
                if (State == SLIDEBARSTATE) {
                  ModAll();
                  ModifyIDCMP(Window, Window->IDCMPFlags & ~MOUSEMOVE);
                  State = SavedState;
                }
                break;
         }
         break;

    case MOUSEMOVE:
         DragBarBox();                        /* slide the bar */
         break;
  }
}

ContNum(num)
  int num;
{
  if (num == 32)
    return(255);
  else
    return(num+FirstContour);
}

RefreshContours()
{
  if ( ContWind ) {

    Ceiling = CurPict->MaxIteration;
    DrawColorBox( ScaledFirst );
    DrawColorBar();
    ReDispPens();
    ModAll();
  }
}

InBarBox()
{
  return(MouseX >= BarLeft + ScaledFirst             &&
         MouseX <= BarLeft + BarWidth  + ScaledFirst &&
         MouseY >= BarBoxTop                         &&
         MouseY <= BarBoxBot                             );
}

StartBarDrag()
{
  BarHotSpot = MouseX - BarLeft - ScaledFirst;
}

DrawColorBar()
{
  register LONG x,s,sx;
  register LONG dx  = XScale + 1;

  register struct RastPort *Rp = ContWind->RPort;

  register UBYTE *ColorPtr = CurPict->Pens;

  sx = BarLeft;

  for (x = 0; x < NumContours; x++ ) {

    SetAPen( Rp, (long) *ColorPtr++ );

    for (s = 0; s < dx; s++) {

      Move(Rp, sx,   BarTop );
      Draw(Rp, sx++, BarBot );
    }
  }
  DrawColorBox( ScaledFirst );
}

DrawColorBox( Contour )
  int Contour;
{
  register LONG Left = BarLeft + Contour;

  DrawBox( ContWind, Left, BarBoxTop, Left + BarWidth, BarBoxBot);
}

DragBarBox()
{
  register int CurX;
  static int OldCurX;

  CurX = MouseX;

  if (CurX == OldCurX)
    return;

  OldCurX = CurX;

  if ( CurX < BarLeft + BarHotSpot )
    CurX = BarLeft + BarHotSpot;
  else
  if ( CurX > BarRight - BarWidth + BarHotSpot )
    CurX = BarRight - BarWidth + BarHotSpot;

  DrawColorBox( ScaledFirst );
  DrawContBox( CurContour, NORMALPEN );

  ScaledFirst = (CurX - BarLeft - BarHotSpot);
  FirstContour = ScaledFirst >> XScale;

  DrawColorBox( ScaledFirst );
  DrawContBox( CurContour, HIGHLIGHTPEN );

  ReDispPens();
}

SetContourPen( Pen )
  USHORT Pen;
{
  register struct Image *Image;

  Image = (struct Image *) SelGadget[ CurContour ]->GadgetRender;

  Image = Image->NextImage;
  Image->PlaneOnOff = Pen;

  RefreshGList( SelGadget[ CurContour ], ContWind, NULL, 1);

  *(CurPict->Pens + CurContour + FirstContour) = Pen;

  UpdateColorBar( Pen );
}

UpdateColorBar( Pen )
  USHORT Pen;
{
  register LONG ContourPos;
  register UBYTE Overlap;
  register LONG  x, sx;

  register struct RastPort *Rp = ContWind->RPort;

  ContourPos = ((CurContour + FirstContour) << XScale);

  Overlap =
      ContourPos == ScaledFirst || ContourPos == ScaledFirst + BarWidth;

  if ( Overlap )
    DrawColorBox( ScaledFirst );

  sx = BarLeft + ((CurContour + FirstContour) << XScale);

  SetAPen( Rp, (long) Pen );

  for (x = 0; x < XScale + 1; x++) {

    Move(Rp, sx,   BarTop );
    Draw(Rp, sx++, BarBot );
  }

  if ( Overlap )
    DrawColorBox( ScaledFirst );
}

SetCurCont(ContNum)
  int ContNum;  /* relative to FirstCont */
{
  if (ContNum == CONTLAST)
    return;

  SaveFirstCont = FirstContour;

  DrawContBox(CurContour, NORMALPEN );
  DrawContBox(ContNum, HIGHLIGHTPEN );

  CurContour = ContNum;
  SetContTitle(ContNum);
}

SetContourHeight(gadget)
  struct Gadget *gadget;
{
  struct  PropInfo *PropInfo;
  ULONG   VertPot;
  SHORT  *Contour;
  int     ContNum;

  PropInfo = (struct PropInfo *) gadget->SpecialInfo;

  VertPot  = PropInfo->VertPot;

  VertPot ^= 0xffff;
  VertPot += 1;

  ContNum = GADG_NUM(gadget->GadgetID);
  Contour = CurPict->Heights + FirstContour + ContNum;

  if (*Contour <= Ceiling)
    *Contour = VertPot * Ceiling >> 16;

  SetCurCont(ContNum);
}

/*
 * Set the contour window's new title
 */
SetContTitle(ContNum)
  int ContNum;
{
  register SHORT Low, High;
  register SHORT *Contour;
  register UBYTE *Color;

  register char *fmt1 = "C: %-3d  P: %-2d  H: %3d-%d";
  register char *fmt2 = "C: %-3d  P: %-2d  H: %3d";

  ContNum += FirstContour;

  Contour = CurPict->Heights + ContNum;

  Color = CurPict->Pens + ContNum;

  High = *Contour;

  if (ContNum != 0) {
    Low  = *(Contour - 1);

    if (Low == High || Low - High == 1) {
      sprintf(ContTitle, fmt2, ContNum, *Color, High);
    } else {
      if (Low < High)
        sprintf(ContTitle, fmt2, ContNum, *Color, High);
      else
        sprintf(ContTitle, fmt1, ContNum, *Color, Low - 1, High);
    }
  } else {

    sprintf(ContTitle, fmt2, ContNum, *Color, High);
  }
  SetWindowTitles(ContWind, ContTitle, NULL);
}

/*
 * Set Selection's pen
 */
DrawContBox(Contour, pen)
  int  Contour;
  LONG pen;
{
  register LONG Left, Right, Top, Bottom;
  register struct RastPort *Rp = ContWind->RPort;

  static LONG LastCont;

  int Cont;

  if ( pen == NORMALPEN ) {

    Cont = LastCont;
  } else {

    LastCont = Cont = Contour + SaveFirstCont - FirstContour;
  }

  if (Cont >= 0 && Cont < DISPCONTS) {

    Left = (6 << XScale) * Cont + CurH->PenLeft - 1;
    Right = Left + (4 << XScale) + 2 + XScale;

    Top = CurV->PenTop - 1;
    Bottom = Top + (4 << YScale) + 2 + YScale;

    SetDrMd(Rp, (LONG) JAM1);
    SetAPen(Rp, pen);
    /*
     * Draw the new box
     */
    Move(Rp, Left,  Top   );
    Draw(Rp, Right, Top   );

    if (pen == HIGHLIGHTPEN) SetAPen( Rp, SHADOWPEN );

    Draw(Rp, Right, Bottom);
    Draw(Rp, Left,  Bottom);

    SetAPen( Rp, (long) pen );

    Draw(Rp, Left,  Top+1 );
  }
} /* DrawContBox */

/*
 *  There was a window pick. Do what we need to do to service it
 */
DoWindowPick(Pict,MouseX,MouseY)
  register struct Picture *Pict;
  register SHORT MouseX,MouseY;
{
  register struct Window *Window = CurPict->Window;
  register USHORT Height;

  if (Pict->Flags & NO_RAM_GENERATE)
    return;

  Height = HeightPicked( Pict, MouseX, MouseY );
  *(CurPict->Heights + CurContour + FirstContour) = Height;
  ModAll();
}

int
HeightPicked( Pict, MouseX, MouseY )
  register struct Picture *Pict;
  register SHORT MouseX,MouseY;
{
  return( *(Pict->Counts + (MouseY - Pict->TopMarg) * Pict->CountX +
                            MouseX - Pict->LeftMarg));
}

/*
 *  Smooth the heights over a subrange of contours
 */
SmoothContours(First,Second)
  int First;
  int Second;
{
  register USHORT Temp;
  register SHORT *StartP,*EndP;
  register float Diff,Start;

  First += SaveFirstCont;
  Second = ContNum(Second);

  if (Second-First != 0) {

    if (Second < First) {
      Temp = First;
      First = Second;
      Second = Temp;
    }

    StartP = CurPict->Heights + First;
    EndP   = CurPict->Heights + Second;

    Start =  (float) *StartP;
    Diff  = ((float) *EndP - Start) / (float) (Second-First);

    if (Diff > -1.0) {
      Diff = -1.0;
    }

    for ( ; First < Second && Start > 0; First++)
      *(StartP++ + 1) = (SHORT) (Start += Diff);

    if (Start == 0) {
      for ( ; First < NumContours; First++) {
        *StartP++ = 0;
      }
    }

    ModAll();
  }
} /* SmoothContours */

/*
 *  Copy the pattern from the palette into pattern area
 */
CopyPattern(First,Second)
  int First, Second;
{
  register int i, spacing;
  register UBYTE *ColorPatt = CurPict->Pens;
  register struct StringInfo *String =
                  (struct StringInfo *) ModGadget->SpecialInfo;

  LONG Spacing;

  UBYTE *Last = ColorPatt + NUMCONTS;

  sscanf( String->Buffer, "%d", &Spacing );
  spacing = Spacing;

  if ( spacing <= 0 ) {
    return;
  }

  First += SaveFirstCont;
  Second = ContNum(Second);

  ColorPatt += First;

  if (First < Second) {

    PattSize = Second - First + 1;
  } else {

    PattSize = First - Second + 1;
    spacing = -spacing;
  }

  for ( i = 0; i < PattSize && ColorPatt >= CurPict->Pens && ColorPatt < Last;
        i++ ) {

    Pattern[ i ] = *ColorPatt;
    ColorPatt += spacing;
  }
  PattSize = i;
} /* CopyPattern */

/*
 *  Set the pattern register to a list of consecutive pens
 */
SetPenPattern(First,Second)
  register int First, Second;
{
  register LONG i, spacing;

  PattSize = Second - First;

  if ( PattSize < 0 ) {
    PattSize = - PattSize;
    spacing = -1;
  } else {
    spacing =  1;
  }
  PattSize += 1;

  for ( i = 0; i < PattSize; i++) {
    Pattern[ i ] = First;
    First += spacing;
  }
} /* SetPenPattern */

/*
 *  Paste the pattern from the palette
 */
PastePattern(First,Second)
  register int First, Second;
{
  register int i, Spacing;
  register UBYTE *ColorPatt = CurPict->Pens;
  register struct StringInfo *String =
              (struct StringInfo *) ModGadget->SpecialInfo;

  LONG spacing;

  register UBYTE *Last = ColorPatt + NUMCONTS;

  if ( PattSize == 0 )
    return;

  sscanf( String->Buffer, "%d", &spacing );

  Spacing = spacing;

  if ( Spacing < 1 )
    return;

  First  += SaveFirstCont;
  ColorPatt += First;
  Second = ContNum(Second);

  if (First < Second ) {

    for ( i = 0; First <= Second && ColorPatt < Last;
                 First += Spacing, i++ ) {

      if ( i == PattSize )
        i = 0;

      *ColorPatt = Pattern[ i ];

      ColorPatt += Spacing;
    }
  } else {

    if (Second == 0) Second = 1;

    for ( i = 0; Second < First && ColorPatt >= CurPict->Pens;
                 First -= Spacing, i++ ) {

      if ( i == PattSize )
        i = 0;

      *ColorPatt = Pattern[ i ];

      ColorPatt -= Spacing;
    }
  }
  DrawColorBox( ScaledFirst );
  DrawColorBar();
  ReDispPens();
} /* PastePattern */

/*
 *  Delete some contours from the contour list
 */
DeleteContours(First,Second)
  register int First, Second;
{
  register USHORT Temp;
  register UBYTE *StartCP, *EndCP;
  register int    Size,i;

  struct StringInfo *String =
         (struct StringInfo *) ModGadget->SpecialInfo;

  LONG spacing;

  sscanf( String->Buffer, "%d", &spacing );

  if ( spacing < 1 )
    return;

  First  += SaveFirstCont;
  Second = ContNum(Second);
  Size = Second - First;

  if (Size) {

    if (Size < 0) {
      Temp = First;
      First = Second;
      Second = Temp;

      Size = -Size;
      Temp = Size % spacing;
      First += Temp;
    }

    StartCP = CurPict->Pens + First;

    if (spacing == 1) {
      EndCP = CurPict->Pens + Second;

      Second = NUMCONTS - Second;

      for (i = 0; i < Second; i++) {
        *StartCP++ = *EndCP++;
      }
    } else {
      EndCP   = StartCP + 1;

      for ( ; First < Second; First += spacing ) {
        for ( i = 0; i < spacing - 1; i++) {
          *StartCP++ = *EndCP++;
        }
        EndCP++;
      }
    }

    while ( StartCP < CurPict->Pens + NUMCONTS ) {
      *StartCP++ = NORMALPEN;
    }

    DrawColorBox( ScaledFirst );
    DrawColorBar();
    ReDispPens();
    ModAll();
  }
} /* DeleteContours */

/*
 * ReDisplay all the contour potentiometer gadgets
 */
ModAll()
{
  register SHORT i;
  register USHORT VertPot;
  register USHORT Height;
  register USHORT PrevHeight;

  register struct Gadget *PropGad = (struct Gadget *) ContGadget[0];
  register struct Picture *Pict = CurPict;

  if (Ceiling > 0) {

    if (FirstContour == 0) {

      PrevHeight = Pict->Heights[ 0 ] + 1;

    } else {

      for (i = 0; i < FirstContour - 1; i++) {

        Height = Pict->Heights[ i ];

        if (Height < PrevHeight) {
          PrevHeight = Height;
        }
      }
    }

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

      Height = CurPict->Heights[ i + FirstContour ];

      SetPotPen( PropGad, PrevHeight, Height );

      if (Height < PrevHeight)
        PrevHeight = Height;

      if ( Height < Ceiling) {

        VertPot  = (Height<<16)/Ceiling;
        if (VertPot > 0)
          VertPot--;
        VertPot ^= 0xffff;
      } else

        VertPot = (USHORT) 0;

      NewModifyProp( PropGad, ContWind, NULL, FREEVERT|PROPBORDERLESS, 0L,
               (long) VertPot, 0L, 0xffff/Ceiling, 1L);

      PropGad = PropGad->NextGadget;
    }
  }
} /* ModAll */

/*
 * ReDisplay all the contour potentiometer gadgets
 */
ShowValid()
{
  register SHORT i;
  register USHORT Height;
  register USHORT PrevHeight;

  register struct Gadget *PropGad = (struct Gadget *) ContGadget[0];
  register struct Picture *Pict = CurPict;

  if (Ceiling > 0) {

    if (FirstContour == 0)
      PrevHeight = Pict->Heights[ 0 ] + 1;
    else
      PrevHeight = Pict->Heights[ FirstContour - 1 ];

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

      Height = CurPict->Heights[ i + FirstContour ];

      if (SetPotPen( PropGad, PrevHeight, Height )) {
        RefreshGList( PropGad, ContWind, NULL, 1);
      }

      if (Height < PrevHeight)
        PrevHeight = Height;

      PropGad = PropGad->NextGadget;
    }
  }
} /* ShowValid */

SetPotPen( PropGad, PrevHeight, Height )
  register struct Gadget *PropGad;
  register USHORT PrevHeight;
  register USHORT Height;
{
  register int place,color;
  register struct Image *Image;
  extern int Num_vp_Colors;

  Image = (struct Image *) PropGad->GadgetRender;

  if (Height >= PrevHeight || Num_vp_Colors == 2)
    color = SHADOWPEN;
  else
    color = HIGHLIGHTPEN;

  if (Image->PlaneOnOff != color) {
    place = RemoveGadget( ContWind, PropGad );
    Image->PlaneOnOff = color;
    AddGadget( ContWind, PropGad, place );
    return(1);
  }
  return(0);
}

/*
 * ReDisplay all the pens gadgets
 */
ReDispPens()
{
  struct Gadget **Gadget = SelGadget;

  register LONG Left = (*Gadget)->LeftEdge;
  register LONG Top = (*Gadget)->TopEdge;
  register LONG Bot = Top + (4 << YScale) - 1;

  register LONG sixx  = 6 << XScale;
  register LONG fourx = (4 << XScale) - 1;

  register struct Image *Image;

  LONG i;
  struct RastPort *Rp = ContWind->RPort;
  UBYTE *Pen = CurPict->Pens + FirstContour;

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

    Image = (struct Image *) (*Gadget)->GadgetRender;

    Image = Image->NextImage;

    SetAPen( Rp, (long) (Image->PlaneOnOff = *Pen++) );

    RectFill( Rp, Left, Top, Left + fourx, Bot);

    Left += sixx;

    Gadget++;
  }

  SetContTitle( 0 );
}

static LONG WindowWidth;
static LONG WindowHeight;

static struct Border *BarBorder;
static struct Border *PenBorder;
static struct Border *ClnBorder;

/*
 * Allocate all the gadgets and things for the contour window
 */
struct Gadget *MakeContours()
{
  struct Gadget   *FirstGadget;
  struct PropInfo *PropInfo;

  register struct Gadget *NextGadget;
  register struct IntuiText *Intui;

  register ULONG i,x,y;
  register ULONG c = 0;

  int fourx = 4 << XScale;
  int foury = 4 << YScale;
  LONG sixx = 6 << XScale;
  LONG sixy = 6 << YScale;

  int Left,Top,Width;

  char *str;

  if ( XScale )
    CurH = &Horiz_II;
  else
    CurH = &Horiz_I;

  if ( YScale )
    CurV = &Verticle_II;
  else
    CurV = &Verticle_I;

  FirstContour = 0;
  SaveFirstCont = 0;

  PenBorder = ClnBorder = BarBorder = NULL;

  BarBorder = ShadowBorder( BEVELEDUP, CurH->BarLeft - 4, CurV->BarTop - 2,
                                       CurH->BarWidth,    CurV->BarHeight);
  if (BarBorder == NULL) goto error;

  PenBorder = ShadowBorder( BEVELEDUP, CurH->PenLeft - 4, CurV->PenTop - 3,
                                       CurH->PenWidth,    CurV->PenHeight);
  if (PenBorder == NULL) goto error;

  Left = CurH->PenLeft + CurH->PenWidth + 2;

  ClnBorder = ShadowBorder( BEVELEDUP, Left,      CurV->PenTop-3,
                                       fourx + 5, CurV->PenHeight);
  if (ClnBorder == NULL) goto error;

  FirstGadget = NextGadget = MakePot( Left + 3, 30 << YScale,
                                     fourx, 32 << YScale, CONTCEIL, 0);
  if (NextGadget == NULL) goto error;

  NextGadget->Activation = GADGIMMEDIATE | FOLLOWMOUSE | RELVERIFY;

  Left = CurH->CmdLeft;
  Top = CurV->CmdTop;

  for (x = 0; x < 6; x++) {

    switch (x) {
      case 0: str = "Paint";  break;
      case 1: str = "Set";    break;
      case 2: str = "Smooth"; break;
      case 3: str = "Cut";    break;
      case 4: str = "Copy";   break;
      case 5: str = "Paste";  break;
    }

    Width = 8 * strlen( str ) + 6;

    NextGadget = NextGadget->NextGadget =
      MakeBool( Left, Top, Width, 13, NORMALPEN, CONTCNTL+x, NULL);

    if (NextGadget == NULL) goto error;

    Intui = NextGadget->GadgetText = ShadowIntui( str, 4, 3);

    if (Intui == NULL) goto error;

    Left += 4 + Width;
  }

  /* Set up color bar below command gadgets */

  BarBoxTop = CurV->BarTop;
  BarTop = BarBot = BarBoxTop + 1;
  BarBot += 4 << YScale;
  BarBoxBot = BarBot + 1;

  BarLeft = BarRight = CurH->BarLeft;
  BarRight += 256 << XScale;
  BarWidth = (DISPCONTS) << XScale;

  Width = 8 * strlen("Last") + 4;

  Top = CurV->PenTop;

  NextGadget = NextGadget->NextGadget =
    MakeBool( BarRight - Width + (2 << XScale), CurV->PenTop - 4, Width, 13,
              NORMALPEN, CONTLAST, NULL);

  if (NextGadget == NULL) goto error;

  Intui = NextGadget->GadgetText = ShadowIntui( "Last", 3, 3);

  if (Intui == NULL) goto error;

  NextGadget->GadgetText = Intui;

  i = CurH->PenLeft;

  /* Make Set of Gadgets */

  for (x = i, y = 0; y < DISPCONTS; x += sixx, y++) {

    SelGadget[y] = NextGadget = NextGadget->NextGadget =
      MakeBool(x, Top, fourx, foury, CurPict->Pens[ y + FirstContour ],
               CONTSEL+y, GADGIMAGE );

    if (NextGadget == NULL) goto error;
  }

  Top += sixy;

  FirstGadget->TopEdge = Top;

  Ceiling = CurPict->MaxIteration;

  /*
   * Allocate the potentiometer gadgets for contour window
   */
  for (x = i, y = 0; y < DISPCONTS; x += sixx, y++) {

    ContGadget[y] = NextGadget = NextGadget->NextGadget =
        MakePot(x, Top, 4 << XScale, 32 << YScale, CONTPOT+y, y);

    if (NextGadget == NULL) goto error;

    NextGadget->Activation = GADGIMMEDIATE | FOLLOWMOUSE | RELVERIFY;

    c = CurPict->Heights[ y ];

    if ( c < Ceiling )
      c = (ULONG) ((((Ceiling - ( c + 1 ))<<16)/(Ceiling)) & 0xffff);
    else
      c = (ULONG) 0;

    PropInfo = (struct PropInfo *) NextGadget->SpecialInfo;

    PropInfo->VertPot = c;
    PropInfo->VertBody = (USHORT) 0xffff/1024;
  }

  Top += 34 << YScale;

  ModGadget = NextGadget = NextGadget->NextGadget =
     MakeString( -28, -12 , 3, 0, "1" );

  if ( NextGadget == NULL ) goto error;

  NextGadget->Flags |= GRELBOTTOM | GRELRIGHT;
  NextGadget->GadgetText = Intui = ShadowIntui( "Mod", 0, -11 );

  if ( Intui == NULL ) goto error;

  WindowHeight = CurV->PenTop + CurV->PenHeight + (2 << YScale);

  if (XScale) {
    WindowWidth = 534;
  } else {
    WindowWidth = 271;
  }
  return( FirstGadget );

error:
  FreeBorder( BarBorder );
  FreeBorder( PenBorder );
  FreeBorder( ClnBorder );
  FreeGadgets( FirstGadget );
  return( NULL );

} /* MakeContours */

static struct Gadget *ContGadgets;

/*
 * Open the Contour window
 */
int
OpenContWind()
{
  register struct Gadget *gadgets;
  register struct RastPort *Rp;

  if (CurPict == NULL)
    return;

  if (ContWind == NULL) {

    gadgets = MakeContours();

    if (gadgets == NULL) {
      DispErrMsg("Can't allocate contour gadget chain",0);
      return(0);
    }
    ContWind = OpenMyWind(&NewCont, screen, NULL, WindowWidth,
                          WindowHeight);

    if (ContWind == NULL) {
      FreeGadgets(gadgets);
      return(0);
    }
    Rp = ContWind->RPort;

    SetAPen( Rp, NORMALPEN );
    RectFill( Rp, LEFTMARG, TOPMARG, WindowWidth, WindowHeight);

    ContGadgets = gadgets;

    BorderWindow( ContWind );

    DrawBorder( Rp, BarBorder, 0L, 0L );
    DrawBorder( Rp, PenBorder, 0L, 0L );
    DrawBorder( Rp, ClnBorder, 0L, 0L );

    FreeBorder( BarBorder );
    FreeBorder( PenBorder );
    FreeBorder( ClnBorder );

    AddGList( ContWind, gadgets, -1L, -1L);

    SetContTitle(0);

    DrawColorBar();
    DrawContBox( CurContour, HIGHLIGHTPEN );

    RefreshGadgets( ContWind->FirstGadget, ContWind, NULL );
    ModAll();
  } else {

    WindowToFront( ContWind );
  }
  ContOpen = 1;
  return( 1 );
} /* OpenContWind */

/*
 * Close the Mand window
 */
CloseContWind()
{
  if (ContWind != NULL) {

    NewCont.LeftEdge = ContWind->LeftEdge;
    NewCont.TopEdge = ContWind->TopEdge;

    CloseMyWind(ContWind,ContGadgets);
  }
  ContWind = NULL;
} /* ClosePalWind */

