/*
 * 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 IntuiMessage handler (also referred to
 * as the command handler.)  This code implements a command-state state
 * machine.
 */

#include "mandp.h"

extern struct Picture *ZoomedPict;

BYTE State;
BYTE Parse_rc;

ProcessCmd(Msg)
  struct IntuiMessage *Msg;
{
  DecodeClass(Msg);         /* decode input by class */
  PostProcessMsg(Msg);      /* set current pen, contour, or range */
  DisplayMsg();             /* Display a message in the title bar */

  if (State == IDLESTATE) {
    SetNormPointer();
  }
}

/*
 * This function serves the following purposes:
 *    1. Reacts to menu items and command gadgets (overriding whatever
 *       the outstanding state is.)
 *    2. Filters of messages that do not affect the state of
 *       user interaction (NEWSIZE, REFRESHWINDOW, CLOSEWINDOW...)
 *    3. It only allows MOUSEBUTTON messages to get past this
 *       routine if they are desired.
 */

DecodeClass(Msg)
  struct IntuiMessage *Msg;
{
  register struct Window  *Window = Msg->IDCMPWindow;
  struct Picture *Pict;

  switch( Msg->Class ) {

         /* These Classes can cause State to be set */

    case MENUPICK:
         HandleMenuPick( Msg );
         break;

    case GADGETDOWN:
         HandleGadgetCmd(Msg);
         break;

    case MOUSEBUTTONS:
         /* filter unwanted SELECTDOWNS and SELECTUPS */
         /* So that each of cmd routines below don't  */
         /* have to ignore them                       */

         if (Msg->IDCMPWindow == ContWind) {

           SlideBarCmd(Msg);
         } else {

           Pict = (struct Picture *) Window->UserData;

           if (Pict != NULL) {

             /* ignore Project buttons outside the picture area */

             if (Msg->Code == SELECTUP || Msg->Code == SELECTDOWN  &&
                 MouseX >= Pict->LeftMarg &&
                 MouseY >= Pict->TopMarg  &&
                 MouseX <  Window->Width  - Pict->RightMarg &&
                 MouseY <  Window->Height - Pict->BotMarg ) {

               DecodeState(Msg);
             }
           }
         }
         break;

         /* this message class cancels any command (i.e. clear state ) */

    case CLOSEWINDOW:
         CloseWinds( Window );
         State = IDLESTATE;
         break;

         /* The response to these message classes depends on what we're
          * doing.
          */

    case MOUSEMOVE:
         DecodeState(Msg);
         break;

    case GADGETUP:
         HandleGadgetCmd(Msg);
      /* DecodeState(Msg); */
         break;

         /* these message classes do not modify state */

    case ACTIVEWINDOW:
         ActivatePict( Window );
         break;

    case NEWSIZE:
         if (Window != BackWind) {
           BorderWindow( Window );

           if (Window->UserData) {
             ScrollPictCmd(Msg);
           }
         }
         break;

    default:
         printf("Unexpected msg class %04x\n",Msg->Class);
         break;
  }
}

DisplayMsg()
{
  char *c;
  c = NULL;

  switch(State) {
  case COPYRIGHTSTATE:  c = "Copyright 1987,1989 Kevin Clague";        break;
  case IDLESTATE:       c = "MandelVroom V2.0 by Kevin Clague";        break;
  case SETCONTSTATE:    c = "You can set color or height";             break;
  case ORBITSTATE:      c = "Press left mouse button in Project";      break;
  case SETJULIASTATE:   c = "Press left mouse button in Mand Project"; break;
  case ZOOMINSTATE:     c = "Place the Zoom box in a Project";         break;
  case COPYRGBSTATE:    c = "Select a color pen to copy RGBs";         break;
  case SPREADRGBSTATE:  c = "Select a color pen to spread RGBs";       break;
  case XCHGRGBSTATE:    c = "Select a color pen to exchange RGBs";     break;
  case CYCLERANGESTATE: c = "Select a color pen to complete range";    break;
  case SMOOTHCONTSTATE: c = "Select a contour pen to smooth heights";  break;
  case CUTCONTSTATE:    c = "Select a contour pen to cut a pattern";   break;
  case COPYCONTSTATE:   c = "Select a contour pen to copy a pattern";  break;
  case PASTECONTSTATE:  c = "Select a contour pen to paste a pattern"; break;
  case HELPSTATE:       c = "Select a menu or gadget for help";        break;
  case SCROLLPICTSTATE: c = "Use the mouse to pan the current project";break;
  case SETHEIGHTSTATE:  c = "Mouse changes contour's lower bound";     break;
  case SLIDERGBSTATE:   c = "Move the mouse to change RGB values";     break;
  case SLIDEBARSTATE:   c = "Move the mouse to scroll contours";       break;
  case RESIZEZOOMSTATE: c = "Move the mouse to size the Zoom box";     break;
  case ZOOMDRAGSTATE:   c = "Move the mouse to drag the Zoom box";     break;
  case PROPRESIZESTATE: c = "Move the mouse to size the Zoom box";     break;
  case SCROLLHELPSTATE: c = "Move the mouse to scroll help info.";     break;
  case SLIDESPEEDSTATE: c = "Move the mouse to change speed";          break;
  }

  /* only display the message if it is a new one */

  if (c && screen->Title != c) {
    SetWindowTitles( CurWind, (char *) -1, c );
  }
}

DecodeState(Msg)
  struct IntuiMessage *Msg;
{
  switch(State) {
    case COPYRIGHTSTATE:
    case IDLESTATE:        DecodeMsg(Msg);      break;
    case COPYRGBSTATE:     CopyRGBCmd(Msg);     break;
    case SPREADRGBSTATE:   SpreadRGBCmd(Msg);   break;
    case XCHGRGBSTATE:     ExchangeRGBCmd(Msg); break;
    case SLIDERGBSTATE:    SlideRGBCmd(Msg);    break;
    case SETHEIGHTSTATE:   SetHeightCmd(Msg);   break;
    case SETCONTSTATE:     SetContCmd(Msg);     break;
    case SMOOTHCONTSTATE:  SmoothContCmd(Msg);  break;
    case CUTCONTSTATE:     CutContCmd(Msg);     break;
    case COPYCONTSTATE:    CopyContCmd(Msg);    break;
    case PASTECONTSTATE:   PasteContCmd(Msg);   break;
    case SLIDEBARSTATE:    SlideBarCmd(Msg);    break;
    case ORBITSTATE:       OrbitCmd(Msg);       break;
    case ZOOMINSTATE:      ZoomInCmd(Msg);      break;
    case RESIZEZOOMSTATE:  ResizeZoomCmd(Msg);  break;
    case QUERYHEIGHTSTATE: QueryHeightCmd(Msg); break;
    case ZOOMDRAGSTATE:    ZoomDragCmd(Msg);    break;
    case PROPRESIZESTATE:  PropResizeCmd(Msg);  break;
    case SETJULIASTATE:    SetJuliaCmd(Msg);    break;
    case SLIDESPEEDSTATE:  SlideSpeedCmd(Msg);  break;
    case CYCLERANGESTATE:  CycleRangeCmd(Msg);  break;
    case SCROLLHELPSTATE:  ScrollHelpCmd(Msg);  break;
    case SCROLLPICTSTATE:  ScrollPictCmd(Msg);  break;
  }
}

/*
 * Set Current pen or current contour.
 */

PostProcessMsg(Msg)
  struct IntuiMessage *Msg;
{
  register struct Window  *Window = Msg->IDCMPWindow;
  struct Gadget *gadget;
  int    id;

  if (Msg->Class == GADGETDOWN) {

    gadget = (struct Gadget *) Msg->IAddress;
    id = gadget->GadgetID;
    switch (WIND_TYPE(id)) {

      case PALTYPE:
           if (GADG_TYPE(id) == PALPENS) {
             SetCurPen(GADG_NUM(id));
           }
           break;

      case CONTYPE:
           if ((GADG_TYPE(id) == CONTSELS || GADG_TYPE(id) == CONTPOTS) &&
             id != CONTLAST) {

             SelContCmd(Msg);
           }
    }
  }
}

/*
 * This is mostly for MOUSEBUTTON related commands (where the MOUSEBUTTONS
 * are commands like drag, close or resize zoom box.)
 */

DecodeMsg(Msg)
  struct IntuiMessage *Msg;
{
  switch( Msg->Class ) {

    case MOUSEBUTTONS:
         /* query height */
         DecodePictMouseButtons( Msg );
         break;
  }
}

HandleGadgetCmd(Msg)
  struct IntuiMessage *Msg;
{
  struct Gadget *gadget;
  int id, type, num;

  if (State == HELPSTATE) {
    HelpGadgetCmd(Msg);
    State = IDLESTATE;
    return;
  }

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

  id   = gadget->GadgetID;
  type = GADG_TYPE(id);

  switch( WIND_TYPE(id)) {

    case PICTTYPE:
         State = IDLESTATE;
         switch (id) {
           case PICTGEN:   GenerateCmd(Msg); break;
           case PICTIN:    ZoomInCmd(Msg);   break;
           case PICTOUT:   ZoomOutCmd(Msg);  break;
           case PICTJULIA: SetJuliaCmd(Msg); break;
         }
         MakeCurProj((struct Picture *) Msg->IDCMPWindow->UserData);
         break;

    case PALTYPE:
         StopCycle();
         switch (type) {
           case PALPENS:          DecodeState(Msg);    break;
           case PALPOTS:          SlideRGBCmd(Msg);    break;
           case PALCNTLS:
                switch (id) {
                  case PALCOPY:   CopyRGBCmd(Msg);     break;
                  case PALRANGE:  SpreadRGBCmd(Msg);   break;
                  case PALEXCG:   ExchangeRGBCmd(Msg); break;
                }
                break;
         }
         break;

    case CYCTYPE:
         switch (type) {
           case CYCRNUMS:         SelRangeCmd(Msg);   break;
           case CYCCNTLS:
                switch (id) {
                  case CYCSPEED:  SlideSpeedCmd(Msg); break;
                  case CYCRANGE:  CycleRangeCmd(Msg); break;
                  case CYCDIR:    ToggleDirCmd(Msg);  break;
                  case CYCON:     CycleOnOffCmd(Msg); break;
                }
                break;

         }
         break;

    case CONTYPE:
         StopCycle();
         switch (type) {
           case CONTSELS:         DecodeState(Msg);   break;
           case CONTPOTS:         SetHeightCmd(Msg);  break;
           case CONTCNTLS:
                switch (id) {
                  case CONTRECOL: PaintCmd(Msg);      break;
                  case CONTSET:   SetContCmd(Msg);    break;
                  case CONTSMTH:  SmoothContCmd(Msg); break;
                  case CONTCUT:   CutContCmd(Msg);    break;
                  case CONTCOPY:  CopyContCmd(Msg);   break;
                  case CONTPASTE: PasteContCmd(Msg);  break;
                  case CONTCEIL:  CeilingCmd(Msg);    break;
                }
                break;
         }
         break;

    case ORBTTYPE:
         OrbitCmd(Msg);
         break;

    case HELPTYPE:
         switch (id) {

           case HELPUP:
           case HELPDOWN:
                Page_File(id);
                break;

           case HELPSCROLL:
                ScrollHelpCmd(Msg);
                break;
         }
  }
}

DecodePictMouseButtons( Msg )
  struct IntuiMessage *Msg;
{
  register struct Node    *zNode;
  register struct Picture *ZoomPict;
  register struct Picture *Pict;
           struct Picture *PictAddr();
  int rc;

  Pict = (struct Picture *) Msg->IDCMPWindow->UserData;

  zNode = Pict->zList.lh_Head;

  rc = NOTHINGHIT;

  while ( rc == NOTHINGHIT && zNode->ln_Succ ) {

    ZoomPict = PictAddr( zNode );

    switch( rc = CheckPictZoomBox( ZoomPict ) ) {

      case ZOOMCLOSEHIT: /* User closed the zoom box */
           ClearZoomBox( ZoomPict );
           break;

      case ZOOMDRAGHIT:
           ZoomedPict = ZoomPict;
           ZoomDragCmd(Msg);
           break;

      case ZOOMRESIZEHIT:
           ZoomedPict = ZoomPict;
           ResizeZoomCmd(Msg);
           break;

      case PROPRESIZEHIT:
           ZoomedPict = ZoomPict;
           PropResizeCmd(Msg);
           break;
    }

    zNode = zNode->ln_Succ;
  }

  if (rc == NOTHINGHIT) {
    QueryHeightCmd(Msg);
  }
}
