/*
 *  NL-Daemon   A program to force old programs to use NL gadget imagery.
 *
 *              Copyright 1989 by Davide P. Cervone.
 *  You may use this code, provided this copyright notice is kept intact.
 */

#include "NL-Handler.h"

static char *program   = PROGRAM;
static char *copyright = COPYRIGHT;


/*
 *  The following are the data for the Image structures used to
 *  replace the standard Intuition gadget images
 */

extern USHORT UpFrontData[UPDEPTH][UPHEIGHT*UPWORDS];
extern USHORT DownBackData[DOWNDEPTH][DOWNHEIGHT*DOWNWORDS];
extern USHORT SizeData[SIZEDEPTH][SIZEHEIGHT*SIZEWORDS];
extern USHORT CloseData[CLOSEDEPTH][CLOSEHEIGHT*CLOSEWORDS];
extern USHORT ZoomData[ZOOMDEPTH][ZOOMHEIGHT*ZOOMWORDS];

extern USHORT LR_UpFrontData[LR_UPDEPTH][LR_UPHEIGHT*LR_UPWORDS];
extern USHORT LR_DownBackData[LR_DOWNDEPTH][LR_DOWNHEIGHT*LR_DOWNWORDS];
extern USHORT LR_SizeData[LR_SIZEDEPTH][LR_SIZEHEIGHT*LR_SIZEWORDS];
extern USHORT LR_CloseData[LR_CLOSEDEPTH][LR_CLOSEHEIGHT*LR_CLOSEWORDS];
extern USHORT LR_ZoomData[LRZOOMDEPTH][LRZOOMHEIGHT*LRZOOMWORDS];

struct Image UpFrontImage =
   {0,0, UPWIDTH,UPHEIGHT,UPDEPTH, &UpFrontData[0][0], 0x03,0x00, NULL};

struct Image DownBackImage =
   {0,0, DOWNWIDTH,DOWNHEIGHT,DOWNDEPTH, &DownBackData[0][0], 0x03,0x00, NULL};

struct Image SizeImage =
   {0,0, SIZEWIDTH,SIZEHEIGHT,SIZEDEPTH, &SizeData[0][0], 0x03,0x00, NULL};

struct Image CloseImage =
   {0,0, CLOSEWIDTH,CLOSEHEIGHT,CLOSEDEPTH, &CloseData[0][0], 0x03,0x00, NULL};

struct Image ZoomImage =
   {-3,0, ZOOMWIDTH,ZOOMHEIGHT,ZOOMDEPTH, &ZoomData[0][0], 0x03,0x00, NULL};


struct Image LR_UpFrontImage =
   {0,0, LR_UPWIDTH,LR_UPHEIGHT,LR_UPDEPTH, &LR_UpFrontData[0][0],
    0x03,0x00, NULL};

struct Image LR_DownBackImage =
   {0,0, LR_DOWNWIDTH,LR_DOWNHEIGHT,LR_DOWNDEPTH, &LR_DownBackData[0][0],
    0x03,0x00, NULL};

struct Image LR_SizeImage =
   {0,0, LR_SIZEWIDTH,LR_SIZEHEIGHT,LR_SIZEDEPTH, &LR_SizeData[0][0],
    0x03,0x00, NULL};

struct Image LR_CloseImage =
   {0,0, LR_CLOSEWIDTH,LR_CLOSEHEIGHT,LR_CLOSEDEPTH, &LR_CloseData[0][0],
    0x03,0x00, NULL};

struct Image LR_ZoomImage =
   {-2,0, LRZOOMWIDTH,LRZOOMHEIGHT,LRZOOMDEPTH, &LR_ZoomData[0][0],
   0x03,0x00,NULL};


/*
 *  SetImage()
 *
 *  Saves the gadget's current image pointer in the SelectRender field
 *  and the width and left edge in the UserData field so that we can 
 *  replace them if NL-Daemon is removed.  Then we set the Render 
 *  pointer to the Image we want, and fix the size and positioning
 *  appropriately.
 */

static void SetImage(theGadget,theImage,x,w)
struct Gadget *theGadget;
struct Image *theImage;
int x,w;
{
   theGadget->SelectRender = theGadget->GadgetRender;
   theGadget->UserData =
      (APTR)((((LONG)(theGadget->LeftEdge)) << 16) | theGadget->Width);
   theGadget->GadgetRender = (APTR)theImage;
   if (x != SAME) theGadget->LeftEdge = x;
   theGadget->Width = theImage->Width - w;
}


/*
 *  SetupGadget()
 *
 *  Changes the gadget imagery from the standard Intuition images to the
 *  New Look images.  Uses the SYSGADGET flag and the Intuition identification
 *  numbers to tell which gadget is which.  Also modifies the gadget's
 *  width and left edge position to fit the new imagery.
 *
 *  Since the gadgets are only copies of the standard ones, changing these
 *  is safe, and does not effect any other window.  Since Intuition cleans
 *  up after the gadgets (and uses static images of its own) replacing
 *  the imagery does not require any special clean up on our part.
 */

void SetupGadgets(theGadget,Depth,Resolution,theWindow)
struct Gadget *theGadget;
int Depth;
ULONG Resolution;
struct Window *theWindow;
{
   int dx = 0;
   
   while (theGadget)
   {
      switch(theGadget->GadgetType & ~GADGETTYPE)
      {
         case SIZING:
            if (Resolution == HIRES)
               SetImage(theGadget,&SizeImage,SAME,0);
              else
               SetImage(theGadget,&LR_SizeImage,SAME,0);
            break;

         case WUPFRONT:
         case SUPFRONT:
            if (Depth > 1)
            {
               if (Resolution == HIRES)
                  SetImage(theGadget,&UpFrontImage,-UpFrontImage.Width+1,0);
                 else
                  SetImage(theGadget,&LR_UpFrontImage,SAME,0);
            }
            break;

         case WDOWNBACK:
         case SDOWNBACK:
            if (Depth > 1)
            {
               if (Resolution == HIRES)
                  SetImage(theGadget,&DownBackImage,
                     -(UpFrontImage.Width+DownBackImage.Width) + 1,0);
                 else
                  SetImage(theGadget,&LR_DownBackImage,SAME,0);
            }
            break;

         case CLOSE:
            if (Resolution == HIRES)
               SetImage(theGadget,&CloseImage,0,0);
              else
               SetImage(theGadget,&LR_CloseImage,0,0);
            break;

         case BOOLGADGET:
            if (theGadget->GadgetID == ZOOMGADG && Depth > 1 && theWindow)
            {
               if (Resolution == HIRES)
               {
                  dx = (theWindow->Flags & WINDOWDEPTH)? 2: 0;
                  SetImage(theGadget,&ZoomImage,theGadget->LeftEdge+dx,3);
               } else {
                  dx = (theWindow->Flags & WINDOWDEPTH)? -2: 0;
                  SetImage(theGadget,&LR_ZoomImage,theGadget->LeftEdge+dx,2);
               }
            }
            break;
      }
      theGadget = theGadget->NextGadget;
   }
}


/*
 *  cOpenWindow()
 *
 *  This is called after a window has been opened:  theWindow is the 
 *  pointer to the opened window.
 *
 *  If the window has standard IntuitionGadgets or if it receives NEWSIZE
 *  IDCMP messages (which means ZOOM-DAEMON may have added a gadget) then
 *  go through the gadget list to replace the imagery.
 *
 *  If the Detail and Block pens are the standard ones, change them to the
 *  ones needed by NL-Daemon.
 *
 *  Once everything is set up, refresh the window imagery.
 */

struct Window *cOpenWindow(theWindow)
struct Window *theWindow;
{
   int Depth;
   ULONG Resolution;

   if (theWindow)
   {
      Depth = theWindow->WScreen->BitMap.Depth;
      Resolution = theWindow->WScreen->ViewPort.Modes & HIRES;
      if ((theWindow->Flags & (WINDOWGADGETS)) ||
          (theWindow->IDCMPFlags & NEWSIZE))
              SetupGadgets(theWindow->FirstGadget,Depth,Resolution,theWindow);
      if (Depth > 1)
      {
         if (theWindow->BlockPen == STDBLOCKPEN)
         {
            theWindow->BlockPen = BLOCKPEN | PENCHANGED;
            if (theWindow->DetailPen == STDDETAILPEN ||
                theWindow->DetailPen == BLOCKPEN)
                   theWindow->DetailPen = DETAILPEN | PENCHANGED;
         }
      }
      RefreshWindowFrame(theWindow);
   }
   return(theWindow);
}


/*
 *  CheckText()
 *
 *  Check the text DrawMode for needed changes.  If the draw mode is 
 *  COMPLEMENT, then change it to JAM1 and set the color.  If it is JAM2,
 *  make sure the background color is OK.  If wither JAM1 or JAM2, check
 *  that the forground color is OK.
 */

static void CheckText(theText)
struct IntuiText *theText;
{
   if (theText)
   {
      switch(theText->DrawMode)
      {
/*
         case COMPLEMENT:
            theText->DrawMode = JAM1;
            theText->FrontPen = DETAILPEN | PENCHANGED;
            break;
*/

         case JAM2:
            if (theText->BackPen == STDBLOCKPEN)
               theText->BackPen = BLOCKPEN | PENCHANGED;
         case JAM1:
            if (theText->FrontPen == BLOCKPEN ||
                theText->FrontPen == STDDETAILPEN)
                   theText->FrontPen = DETAILPEN | PENCHANGED;
            break;
      }
   }
}


/*
 *  CheckItemList()
 *
 *  Look through a MenuItem list and check each item for IntuiTexts
 *  that may need to be changed.  Also check any sub-menus.
 */

static void CheckItemList(theItem)
struct MenuItem *theItem;
{
   while (theItem)
   {
      if (theItem->Flags & ITEMTEXT)
      {
         CheckText(theItem->ItemFill);
         if (theItem->Flags & HIGHIMAGE) CheckText(theItem->SelectFill);
      }
      CheckItemList(theItem->SubItem);
      theItem = theItem->NextItem;
   }
}
   

/*
 *  cSetMenuStrip()
 *
 *  Our replacement for SetMenuStrip.  It is called before the real
 *  set menu strip.
 *
 *  If the window has had it's BlockPen altered, then look through
 *  each menu for IntuiTexts for IntuiTexts that may need to be changed.
 */

void cSetMenuStrip(theWindow,theMenu)
struct Window *theWindow;
struct Menu *theMenu;
{
   if (theWindow->BlockPen & PENCHANGED)
   {
      while (theMenu)
      {
         CheckItemList(theMenu->FirstItem);
         theMenu = theMenu->NextMenu;
      }
   }
}

struct Screen *cOpenScreen(theScreen)
struct Screen *theScreen;
{
   if (theScreen)
   {
      if (theScreen->BitMap.Depth > 1)
      {
         SetupGadgets(theScreen->FirstGadget,theScreen->BitMap.Depth,
                     (theScreen->ViewPort.Modes & HIRES),NULL);
         if (theScreen->BlockPen == STDBLOCKPEN)
         {
            theScreen->BlockPen = BLOCKPEN | PENCHANGED;
            if (theScreen->DetailPen == STDDETAILPEN ||
                theScreen->DetailPen == BLOCKPEN)
                   theScreen->DetailPen = DETAILPEN | PENCHANGED;
         }
         ShowTitle(theScreen,(theScreen->Flags & SHOWTITLE)? TRUE: FALSE);
      }
   }
   return(theScreen);
}
