/*
**     $VER: HandleIntuiMessage.c V0.01 (14-06-95)
**
**     Author:  Gerben Venekamp
**     Updates: 14-06-95  Version 0.01      Initial module
**
**  HandleIntuiMessages.c waits for a message and acts accordingly to it.
**
*/

#include <exec/types.h>
#include <intuition/intuition.h>
#include <proto/exec.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/intuition.h>

#include "IFFConverter.h"

#define MouseCoordsTextX 140L
#define MouseCoordsTextY 1L

// Defining Variables
BOOL PictureValid = FALSE;
BOOL Clipping = FALSE;
BOOL ChangeActivationWindow = TRUE;
BOOL DrawHairCross;

enum ByteBoundry ByteBoundry = BB_None;   // initialise with default value.

UWORD PicWidth;
UWORD PicHeight;
UWORD PicDepth;

ULONG PicSize;

// This is a structure, because we need to pass these variables to another module.
IFFClip_s IFFClip;

// Set 'OldClipLeft' to a value < 0, so when drawing the clip rectangle
// for the first time, we don't REMOVE the rectangle. Because none
// has been drawn.
WORD OldClipLeft = -1;
WORD OldClipTop;
WORD OldClipRight;
WORD OldClipBottom;

// Same here for 'OldMouseX' as 'OldClipLeft' above. Just that it is
// for the hot cursor point cross.
WORD OldMouseX = -1;
WORD OldMouseY;

UBYTE *MouseCoords;
char NoMouseCoords[] = "---- × ----";     // String length should be exactly the same as in IText_MouseCoords

struct IntuiText IText_MouseCoords = {
   1, 2,
   JAM2,
   0, 0,
   NULL,
   "---- × ----",
   NULL,
};

// Defining protos
void HandleIntuiMessages(void);
void HandleClipping_Mouse(WORD, WORD);
void HandleClipping_Gadget(void);
void DrawClipRect(struct RastPort *, UWORD, UWORD, UWORD, UWORD);
void DrawCross(struct RastPort *, UWORD, UWORD);
void MakeByteBoundry(WORD *, BOOL);
void UpdateClipping(void);


/*
**  HandleIntuiMessages()
**
**     Waits for an events to happen. This done through the Wait(...)
**     call. If a signal comes in, 'HandleIntuiMessages' gets the message
**     associated with the signal from the right messageport. The signal
**     can come from either the 'PanelWindow' or 'ViewWindow'. The same
**     code is used to handle the message from both screens. This is SAVE,
**     because all messages generated by the 'ViewWindow' are shared by
**     the 'PanelWindow'. The additional messages generated by the
**     'PanelWindow' are only generated by pressing gadgets. These
**     gadgets ONLY appear on the 'PanelWindow'.
**
**  pre:  None.
**  post: None.
**
*/
void HandleIntuiMessages()
{
   BOOL ExitLoop = FALSE;
   BOOL PanelInFront = TRUE;
   BOOL RemoveInfoWindow;
   
   ULONG Signals;
   ULONG PanelSignal = 1L << PanelWindow->UserPort->mp_SigBit;
   ULONG ViewSignal  = 1L << ViewWindow ->UserPort->mp_SigBit;
   ULONG InfoSignal  = NULL;

   struct IntuiMessage *ConverterMessage = NULL;
   SavePicStruct_t PictureToSave;

   // Make 'MouseCoords' point to the right text.
   MouseCoords = IText_MouseCoords.IText;

   // Print the mouse coordinates one time. This is because when we
   // startup, no picture is loaded and 'PrintIText' inside
   // 'case IDCMP_MOUSEMOVE:' will never be called, until a good picture
   // is loaded.
   PrintIText(&(PanelScreen->RastPort), &IText_MouseCoords, MouseCoordsTextX, MouseCoordsTextY);

   do {
      Signals = Wait(PanelSignal | ViewSignal | InfoSignal);
      RemoveInfoWindow = FALSE;
      
      do {
         if( Signals & PanelSignal )    //  Check if 'PanelWindow' sent the message.
            ConverterMessage = GT_GetIMsg(PanelWindow->UserPort);
         else
            if( Signals & ViewSignal )  //  Check if 'ViewWindow' sent the message.
               ConverterMessage = GT_GetIMsg(ViewWindow->UserPort);
            else
               if( Signals & InfoSignal )  // Check if 'InfoWindow' sent the message.
                  ConverterMessage = GT_GetIMsg(InfoWindow->UserPort);
               
         if(ConverterMessage )   // Did a valid message appear?
         {
            switch( ((struct Gadget *) ConverterMessage->IAddress)->GadgetID )
            {
               LONG TempLong, TempLong2;
               
               case GD_Quit:
                  FadeColours( FADE_DOWN, 320, ViewScreen );
                  ExitLoop = TRUE;
                  break;
                  
               case GD_Load:
                  CloseThisWindow(&InfoWindow);
                  InfoSignal = NULL;
                  PositionScreen(PanelScreen, 0, 12);
                  GetGadgetStatus(GD_FileMode, GTCY_Active, &TempLong,
                                               TAG_DONE);
                  LoadPicture( (enum FileModeType) TempLong);
                  PositionScreen(PanelScreen, PubScreenHeight-PanelHeight, 12);
                  PrintIText( &(PanelScreen->RastPort), &IText_MouseCoords, MouseCoordsTextX, MouseCoordsTextY );
                  break;
                  
               case GD_Save:                  
                  CloseThisWindow(&InfoWindow);
                  InfoSignal = NULL;
                  PositionScreen(PanelScreen, 0, 12);
                  GetGadgetStatus(GD_FileMode, GTCY_Active, &TempLong,
                                               TAG_DONE);
                  GetGadgetStatus(GD_RenderMode, GTCY_Active, &TempLong2,
                                                 TAG_DONE);
                  SavePicture( &PictureToSave );
//                  SavePicture(struct Screen *, enum FileModeType, enum RenderModeType, IFFClip_s *);
                  PositionScreen(PanelScreen, PubScreenHeight-PanelHeight, 12);
                  PrintIText(&(PanelScreen->RastPort), &IText_MouseCoords, MouseCoordsTextX, MouseCoordsTextY);
                  break;
                  
               case GD_ClipWidth:
                  GetGadgetStatus(GD_ClipWidth, GTIN_Number, &TempLong,
                                                TAG_DONE);
                  if(TempLong != 0)
                  {
                     if( TempLong >= 1 )
                        IFFClip.ClipWidth = TempLong - 1;
                     else
                        IFFClip.ClipWidth = TempLong + 1;
                        
                     HandleClipping_Gadget();
                  }
                  break;
                  
               case GD_ClipHeight:
                  GetGadgetStatus(GD_ClipHeight, GTIN_Number, &TempLong,
                                                 TAG_DONE);
                  if(TempLong != 0)
                  {
                     if( TempLong >= 1 )
                        IFFClip.ClipHeight = TempLong - 1;
                     else
                        IFFClip.ClipHeight = TempLong + 1;
                        
                     HandleClipping_Gadget();
                  }
                  break;
                  
               case GD_ClipLeft:
                  GetGadgetStatus(GD_ClipLeft, GTIN_Number, &TempLong,
                                               TAG_DONE);
                  IFFClip.ClipWidth = IFFClip.ClipWidth - TempLong + IFFClip.ClipLeft;
                  IFFClip.ClipLeft = TempLong;
                  HandleClipping_Gadget();
                  break;
                  
               case GD_ClipTop:
                  GetGadgetStatus(GD_ClipTop, GTIN_Number, &TempLong,
                                              TAG_DONE);
                  IFFClip.ClipHeight = IFFClip.ClipHeight - TempLong + IFFClip.ClipTop;
                  IFFClip.ClipTop = TempLong;
                  HandleClipping_Gadget();
                  break;
                  
               case GD_DrawCross:
                  GetGadgetStatus(GD_DrawCross, GTCB_Checked, &TempLong,
                                                TAG_DONE);
                  DrawHairCross = (BOOL)TempLong;
                  break;
               
               case GD_Info:
                  InfoSignal = DisplayInfo();
                  break;
                  
               case GD_ByteBoundry:
                  GetGadgetStatus(GD_ByteBoundry, GTMX_Active, &ByteBoundry,
                                                  TAG_DONE);
                  break;
            }
            
            switch(ConverterMessage->Class)
            {
               case IDCMP_MOUSEMOVE:
                  if( ((PanelWindow->MouseY < 0) || Clipping) && PictureValid )
                  {
                     WORD MouseX = ViewWindow->MouseX;
                     WORD MouseY = ViewWindow->MouseY;
                     
                     MakeByteBoundry( &MouseX, Clipping );
                        
                     if(MouseX < 0         ) MouseX = 0;
                     if(MouseX >= PicWidth ) MouseX = PicWidth-1;
                     if(MouseY < 0         ) MouseY = 0;
                     if(MouseY >= PicHeight) MouseY = PicHeight-1;
                     
                     MakeDecimal(MouseX, MouseCoords,   4);
                     MakeDecimal(MouseY, MouseCoords+7, 4);
                     PrintIText(&(PanelScreen->RastPort), &IText_MouseCoords, MouseCoordsTextX, MouseCoordsTextY);
                     
                     if( !Clipping )
                     {
                        if( OldMouseX >= 0 )
                           DrawCross( &(ViewScreen->RastPort), OldMouseX, OldMouseY );
                        DrawCross( &(ViewScreen->RastPort), MouseX, MouseY );
                        
                        OldMouseX = MouseX;
                        OldMouseY = MouseY;
                     }
                     else
                        HandleClipping_Mouse( MouseX, MouseY );
                  }
                  else
                  {
                     UWORD i;
                     UBYTE *copy1 = MouseCoords;
                     UBYTE *copy2 = NoMouseCoords;
                     
                     for(i=0; i<sizeof(NoMouseCoords); i++)
                        *copy1++ = *copy2++;
                        
                     PrintIText(&(PanelScreen->RastPort), &IText_MouseCoords, MouseCoordsTextX, MouseCoordsTextY);
                     
                     if( OldMouseX >= 0 )
                        DrawCross( &(ViewScreen->RastPort), OldMouseX, OldMouseY );
                     OldMouseX = -1;
                  }
                  break;
                  
               case IDCMP_MOUSEBUTTONS:
                  if( ConverterMessage->Code == IECODE_RBUTTON )
                  {
                     ULONG register ScreenDepthFlag;
                     
                     if( PanelInFront )
                        ScreenDepthFlag = SDEPTH_TOBACK;
                     else
                        ScreenDepthFlag = SDEPTH_TOFRONT;
                     
                     ScreenDepth(PanelScreen, ScreenDepthFlag | SDEPTH_INFAMILY, NULL);
                     PanelInFront = !PanelInFront;
                  }
                  
                  if( (ConverterMessage->Code == IECODE_LBUTTON) && PictureValid )
                  {
                     if( PanelWindow->MouseY < 0 )
                     {
                        IFFClip.ClipPointX = ViewWindow->MouseX;
                        IFFClip.ClipPointY = ViewWindow->MouseY;
                        
                        Clipping = TRUE;
                        
                        DrawCross( &(ViewScreen->RastPort), OldMouseX, OldMouseY ); 
                        HandleClipping_Mouse( IFFClip.ClipPointX, IFFClip.ClipPointY );
                     }
                  }
                  else
                     if( ConverterMessage->Code == (IECODE_LBUTTON | IECODE_UP_PREFIX) )
                     {
                        if( Clipping == TRUE )
                        {
                           OldMouseX = ViewWindow->MouseX;
                           OldMouseY = ViewWindow->MouseY;
                           DrawCross( &(ViewScreen->RastPort), OldMouseX, OldMouseY ); 
                        }
                        Clipping = FALSE;
                     }
                  break;
                  
               case IDCMP_ACTIVEWINDOW:
                  RemoveInfoWindow = TRUE;
                  break;
            }  // END switch
         }   // END if

         GT_ReplyIMsg(ConverterMessage);
         
      } while (ConverterMessage);   // More messages?
      
      if( RemoveInfoWindow )
      {
         CloseThisWindow(&InfoWindow);
         InfoSignal = NULL;
      }
      
   } while (!ExitLoop);   // Loop until exit.
}


/*
**  HandlClipping_Mouse(MouseX, MouseY)
**
**     Handle clipping when the mouse moved.
**
**  pre:  MouseX, MouseY - Current x,y coordinates of the mouse.
**  post: None.
**
*/
void HandleClipping_Mouse(register WORD MouseX, register WORD MouseY)
{
   if(MouseX < 0         ) MouseX = 0;
   if(MouseX >= PicWidth ) MouseX = PicWidth-1;
   if(MouseY < 0         ) MouseY = 0;
   if(MouseY >= PicHeight) MouseY = PicHeight-1;
   
   if( MouseX >= IFFClip.ClipPointX )
      IFFClip.ClipLeft = IFFClip.ClipPointX;
   else
      IFFClip.ClipLeft = MouseX;
      
   if( MouseY >= IFFClip.ClipPointY )
      IFFClip.ClipTop  = IFFClip.ClipPointY;
   else
      IFFClip.ClipTop  = MouseY;
   
   if( (IFFClip.ClipWidth = MouseX - IFFClip.ClipPointX) < 0 )
      IFFClip.ClipWidth = -IFFClip.ClipWidth;
      
   if( (IFFClip.ClipHeight = MouseY - IFFClip.ClipPointY) < 0 )
      IFFClip.ClipHeight = -IFFClip.ClipHeight;
   
   IFFClip.ClipSize = ((IFFClip.ClipWidth + 8) >> 3) * (IFFClip.ClipHeight + 1) * PicDepth;
   
   UpdateClipping();
   
}


/*
**  HandleClipping_Gadget()
**
**     Handle all clipping when one or more of the clipping gadgets has changed.
**
**  pre:  None.
**  post: None.
**
*/
void HandleClipping_Gadget()
{
   // Check if 'ClipWidth' is negative.
   if( IFFClip.ClipWidth < 0 )
   {
      // Negative 'ClipWidth' makes little sence, so make it postive
      // and adjust 'ClipLeft' to compensate for negative width.
      IFFClip.ClipWidth = -IFFClip.ClipWidth;
      IFFClip.ClipLeft = IFFClip.ClipLeft - IFFClip.ClipWidth;
   }
   
   // Check if 'ClipHeight' is negative.
   if( IFFClip.ClipHeight < 0 )
   {
      // Negative 'ClipHeight' makes little sence, so make it postive
      // and adjust 'ClipTop' to compensate for negative height.
      IFFClip.ClipHeight = -IFFClip.ClipHeight;
      IFFClip.ClipTop = IFFClip.ClipTop - IFFClip.ClipHeight;
   }
   
   if( IFFClip.ClipLeft < 0 )
      // 'ClipLeft' cannot be smaller than 0! So, when nagative, make it 0.
      IFFClip.ClipLeft = 0;
   else
      if( IFFClip.ClipLeft >= PicWidth )
         // 'ClipLeft' cannot be greater than 'PicWidth'.
         IFFClip.ClipLeft = PicWidth - 1;
   
   if( IFFClip.ClipTop < 0 )
      // 'ClipTop' cannot be negative. Make it 0.
      IFFClip.ClipTop = 0;
   else
      if( IFFClip.ClipTop >= PicHeight )
         // 'ClipTop' cannot be greater than 'PicHeight'.
         IFFClip.ClipTop = PicHeight - 1;
   
   // See whether 'ClipWidth' and 'ClipHeight' still fits the screen boundry.
   if( (IFFClip.ClipWidth + IFFClip.ClipPointX) > PicWidth )
      IFFClip.ClipWidth = PicWidth - IFFClip.ClipLeft - 1;
   
   if( (IFFClip.ClipHeight + IFFClip.ClipPointY) > PicHeight )
      IFFClip.ClipHeight = PicHeight - IFFClip.ClipTop - 1;
   
   IFFClip.ClipSize = ((IFFClip.ClipWidth + 8) >> 3) * (IFFClip.ClipHeight + 1) * PicDepth;
   UpdateClipping();
}


/*
**  UpdateClipping()
**
**     'UpdateClipping' preforms a total update of the clipping. This
**     means that the old Clip rectangle is ereased and the new one
**     drawn. Also, the gadget containing size and offset, are updated.
**
**  pre:  None.
**  post: None.
**
*/
void UpdateClipping()
{
   UpdateDimensions(GD_ClipLeft,   IFFClip.ClipLeft,
                    GD_ClipTop,    IFFClip.ClipTop,
                    GD_ClipWidth,  IFFClip.ClipWidth + 1,
                    GD_ClipHeight, IFFClip.ClipHeight + 1,
                    GD_ClipSize,   IFFClip.ClipSize,
                    GD_Sentinal);

   if( OldClipLeft >= 0 )
      DrawClipRect( &(ViewScreen->RastPort), OldClipLeft, OldClipTop, OldClipRight, OldClipBottom );
   DrawClipRect( &(ViewScreen->RastPort), IFFClip.ClipLeft, IFFClip.ClipTop, IFFClip.ClipLeft + IFFClip.ClipWidth, IFFClip.ClipTop + IFFClip.ClipHeight );
   
   OldClipLeft   = IFFClip.ClipLeft;
   OldClipTop    = IFFClip.ClipTop;
   OldClipRight  = IFFClip.ClipLeft + IFFClip.ClipWidth;
   OldClipBottom = IFFClip.ClipTop  + IFFClip.ClipHeight;
}


/*
**  DrawClipRect(rp, X1, Y1, X2, Y2)
**
**     Draws a rectangle.
**
**  pre:  rp - pointer to the destination RastPort.
**        X1, Y1 - x, y coordinates of rectangle.
**        X2, Y2 - x, y coordinates of rectangle.
**  post: None.
**
*/
void DrawClipRect(struct RastPort *rp, UWORD X1, UWORD Y1, UWORD X2, UWORD Y2)
{
   register UBYTE ViewDrawMode = GetDrMd( &(ViewScreen->RastPort) );

   SetDrMd( &(ViewScreen->RastPort), COMPLEMENT );

   Move(rp, X1, Y1);
   
   Draw(rp, X2, Y1);
   Draw(rp, X2, Y2);
   Draw(rp, X1, Y2);
   Draw(rp, X1, Y1);

   SetDrMd( &(ViewScreen->RastPort), ViewDrawMode );
}


/*
**  DrawCross(rp, X, Y)
**
**     Draw a cross to indicate the cursor hot point.
**
**  pre:  rp- pointer to the destination RastPort
**        X, Y - x, y coordinates of cursor hot point.
**  post: None.
**
*/
void DrawCross(struct RastPort *rp, UWORD X, UWORD Y)
{
   register UBYTE ViewDrawMode;

   if( DrawHairCross )
   {
      ViewDrawMode = GetDrMd( &(ViewScreen->RastPort) );
      
      SetDrMd( &(ViewScreen->RastPort), COMPLEMENT );
      
      Move(rp, 0, Y);
      Draw(rp, (ViewScreen->Width) - 1, Y);
      
      Move(rp, X, 0);
      Draw(rp, X, (ViewScreen->Height) - 1);

      SetDrMd( &(ViewScreen->RastPort), ViewDrawMode );
   }
}


/*
**  MakeByteBoundry( coord )
**
**     Depending on the type of Boundry coord gets a new value.
**     There are several different Boundry types:
**     None   - No changes to coord.
**     Type 1 - The width of the clip reagon is a multple of 8.
**     Type 2 - The left coordinate of the clip reagon is a multiple of 8.
**     Type 3 - The left and width of the clip reagon are both a multiple of 8.
**     
**  pre:  coord - Pixel values.
**  post: coord - Pixel values according to ByteBoundry.
**
*/
void MakeByteBoundry(WORD *coord, BOOL Clipping)
{

   switch( ByteBoundry )   
   {
      case BB_Type1:
         *coord = (*coord +7) & 0xfff8;
      case BB_Type2:
         if( Clipping )
            *coord = (*coord +7) & 0xfff8;
      case BB_Type3:
         break;      
   }
}
