#include "snap.h"

#define MINWIDTH 75
#define MINHEIGHT 15

/* Window structure for snapped gfx */
struct NewWindow Nw = {
  0, 1,             /* LeftEdge, TopEdge  */
  0, 0,             /* Width, Height */
  -1, -1,           /* DetailPen, BlockPen */
  NULL,             /* IDCMPFlags */
  WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SMART_REFRESH,
  NULL, NULL,       /* FirstGadget, CheckMark */
  (UBYTE *)"Snap © 1989 Mikael Karlsson & Sirius Software",
  NULL, NULL,       /* Screen, BitMap */
  32, 32,           /* MinWidth, MinHeight */
  -1, -1,           /* MaxWidth, MaxHeight */
  WBENCHSCREEN      /* Type */
};

LONG xl; /* leftmost x position */
LONG xr; /* rightmost x position */
LONG yt; /* topmost y position */
LONG yb; /* bottommost y position */
LONG mx, my; /* Mouse position in pixels */

#define GfxFrame 4L
IMPORT Point OldFrame[];
IMPORT Point NewFrame[];
IMPORT LONG OFType;        /* Old frame type: ShortFrame/LongFrame */
IMPORT UWORD Ptrn;

STATIC LONG TitleBarHeight;
STATIC LONG width, height;
IMPORT struct RastPort MyRP;
IMPORT struct BitMap MyBM;
IMPORT struct Screen *theScreen;
IMPORT struct Layer_Info *LockedLayerInfo;
IMPORT struct RastPort rp;
IMPORT UWORD CrawlPtrn;

IMPORT LONGBITS cancelsignal, donesignal, movesignal, clicksignal, timersignal;
IMPORT WORD action;

VOID FixTitleHeight()
{
    struct Screen WBScreen;
    if (GetScreenData(&WBScreen, (LONG)sizeof(struct Screen), WBENCHSCREEN, NULL)) {
          /* Now this is a good practice */
        TitleBarHeight = WBScreen.RastPort.TxHeight+2;
    } else {
          /* Sorry, but I don't realise how this could fail.
             Well, if we're snapping on another screen and
             WB is closed and it can't be opened by GetScreenData()...
             Anyway, IF this should happen -- Use Topaz 8 */
        TitleBarHeight = 10;
    }
}

/* SnapGfx is the actual graphics snapper.
** It steals the bitmap data from the given rastport
** and puts it in a separate bitmap.
** It also prepares the NewWindow structure according
** to the snapped bitmap.
** The coordinates are assumed to be valid.
*/

WORD SnapGfx(rp)
struct RastPort *rp;
{
    REGISTER UBYTE i;
    width = xr - xl;
    height = yb - yt;
      /* Set up a nice bitmap */
    InitBitMap(&MyBM, (long)rp->BitMap->Depth, width, height);
      /* Get a handle on the bitmap */
    InitRastPort(&MyRP);
    MyRP.BitMap = &MyBM;
    if (!AllocPlanes(&MyBM, width, height)) {
        FreePlanes(&MyBM, width, height);
        return 0;
    }
      /* Copy the selected part of the screen */
    ClipBlit(rp, xl, yt, &MyRP, 0L, 0L, width, height, 0xC0L);
    Nw.LeftEdge = xl;
    Nw.TopEdge = yt;
    Nw.Width = width+4;                  /* Two pixels on each side */
    Nw.Height = height+TitleBarHeight+1; /* Bar above, one below */
    Nw.MinWidth = 0;
    Nw.MaxWidth = 0;
    Nw.MinHeight = 0;
    Nw.MaxHeight = 0;
    return 1;
}

VOID ExtendGfx()
{
    /* Fix which row we're talking about */
    if (my-yt < yb-my) {       /* Find closest row */
        yt = my;               /* change top row */
    } else {
        yb = my;               /* change bottom row */
    }
    if (mx-xl < xr-mx) {
        xl = mx;
    } else {
        xr = mx;
    }
}

VOID gfx_frame()
{
    NewFrame[0].x = xl;  NewFrame[0].y = yt;
    NewFrame[1].x = xr;  NewFrame[1].y = yt;
    NewFrame[2].x = xr;  NewFrame[2].y = yb;
    NewFrame[3].x = xl;  NewFrame[3].y = yb;
    NewFrame[4].x = xl;  NewFrame[4].y = yt;
    draw_frame(GfxFrame);
}


WORD HandleGfx()
{
    theScreen = WhichScreen();   /* Find out where we are */
    if (!theScreen) {            /* Don't know? Forget it. */
        action = noaction;
        return 0;
    }
      /* Lock everything - find out what happens */
    LockedLayerInfo = &theScreen->LayerInfo;
    LockLayers(LockedLayerInfo);

      /* Get a copy. Don't mess with somebody else's RP. */
    CopyMem(&theScreen->RastPort, &rp, (long)sizeof(struct RastPort));
    SetDrMd(&rp, COMPLEMENT);
    Ptrn = CrawlPtrn;
    SetDrPt(&rp, Ptrn);

    xl = theScreen->MouseX-9;
    if (xl<0) {
        xl = 0;
    }
    yt = theScreen->MouseY-9;
    if (yt<0) {
        yt = 0;
    }
    xr = xl + 9;
    if (xr>=theScreen->Width) {  /* Check those corners. Check those corners. */
        xr = theScreen->Width-1;
    }
    yb = yt + 9;
    if (yb>=theScreen->Height) {
        yb = theScreen->Height-1;
    }
    OFType = 0L;
    gfx_frame();

    FOREVER {
        REGISTER LONGBITS sig =
          Wait(movesignal|clicksignal|cancelsignal|donesignal|timersignal);

        if ((sig & timersignal) && (CrawlPtrn != 0xffff)) {
            crawl_frame(1L);
        }

        if (sig & movesignal || sig & clicksignal) {
            mx = theScreen->MouseX;
            if (mx>=theScreen->Width) {
                mx = theScreen->Width-1;
            }
            my = theScreen->MouseY;
            if (my>=theScreen->Height) {
                my = theScreen->Height-1;
            }
            ExtendGfx();
            gfx_frame();
        }
        if (sig & cancelsignal) {          /* Cancelled? */
            erase_frame();
            UnlockLayers(LockedLayerInfo);
            action = noaction;
            return 0;
        }
        if (sig & donesignal) {            /* Finished. Copy gfx. */
            SHORT goodsnap = 0;
            erase_frame();
            if (xr<xl+MINWIDTH) {          /* Can't have too small windows */
                xr = xl+MINWIDTH;
            }
            if (xr>=theScreen->Width) {
                xl -= xr-theScreen->Width-1;
                xr = theScreen->Width-1;
            }
            if (yb<yt+MINHEIGHT) {
                yb = yt+MINHEIGHT;
            }
            if (yb>=theScreen->Height) {
                yt -= yb-theScreen->Height-1;
                yb = theScreen->Height-1;
            }
            FixTitleHeight();
            goodsnap = SnapGfx(&rp); /* Snap! */
            UnlockLayers(LockedLayerInfo);
            if (goodsnap) {
                REGISTER struct Window *MyWin;
                if (MyWin = opensharedwindow(&Nw))
                      /* Put gfx in our new window */
                    ClipBlit(&MyRP, 0L, 0L,
                      MyWin->RPort, 2L, TitleBarHeight, width, height, 0xC0L);
                FreePlanes(&MyBM, width, height);  /* Give some mem back */
            } else { /* Good question */
            }
            action = noaction;
            return 0;
        }
    }
}
