/* Auto: make
*/

struct Screen *WhichScreen();
struct Window *WhichWindow();

IMPORT struct XSizeRsrc *XSizeRsrc;
IMPORT WORD OF;

struct Screen *s;
struct Window *w;
struct RastPort rp;
struct Layer_Info *LockedLayerInfo;

WORD mx, my;
WORD xl, yt, xr, yb;
WORD oxl, oyt, oxr, oyb;
WORD minx, maxx, miny, maxy;
WORD leftx, rightx, topy, bottomy;

WORD state = waiting;

#define InGadget(w, mx, my) \
(((w->Height - 10) < my) && (my < (w->Height)) &&   \
 ((w->Width - 17) < mx) && (mx < (w->Width)))

#define KillEvent() ev->ie_Class = IECLASS_NULL

#define GetSMousePos()                                  \
{                                                       \
    mx = s->MouseX + s->ViewPort.RasInfo->RxOffset;     \
    my = s->MouseY + s->ViewPort.RasInfo->RyOffset;     \
    if (mx < 0)             mx = 0;                     \
    if (mx >= s->Width)     mx = s->Width - 1;          \
    if (my < 0)             my = 0;                     \
    if (my >= s->Height)    my = s->Height - 1;         \
}

#define GetWMousePos() { mx = w->MouseX; my = w->MouseY; }

struct InputEvent *Waiting(ev)
REGISTER struct InputEvent *ev;
{
    if (ev->ie_Class == IECLASS_RAWMOUSE && ev->ie_Code == IECODE_LBUTTON) {
        if ((s = WhichScreen()) && (w = WhichWindow(s)) &&
          (w->Flags & WINDOWSIZING)) {  /* Ok, we've got a sizable window */
            GetWMousePos();
            if (InGadget(w, mx, my) ||
              (ev->ie_Qualifier & XSizeRsrc->qual)) {
                state = startframe;
                SetUpForFrame();
                KillEvent();
            }
        }
    }
    return ev;
}

struct InputEvent *StartFrame(ev)
REGISTER struct InputEvent *ev;
{
    if (ev->ie_Class == IECLASS_RAWMOUSE) {
        if (ev->ie_Code == IECODE_LBUTTON+IECODE_UP_PREFIX) {
            KillEvent();
            EraseFrame();
            UnlockLayers(LockedLayerInfo);
            state = waiting;
        } else if (ev->ie_Code == IECODE_NOBUTTON) {
              /* Skip consecutive move events */
            while (ev->ie_NextEvent &&
              (ev->ie_NextEvent->ie_Class == IECLASS_TIMER ||
               (ev->ie_NextEvent->ie_Class == IECLASS_RAWMOUSE &&
                ev->ie_NextEvent->ie_Code == IECODE_NOBUTTON))) {
                ev = ev->ie_NextEvent;
            }
            GetSMousePos();
            if (mx <= xl) {
                leftx = 1;
                state = dragging;
            } else if (mx >= xr) {
                rightx = 1;
                state = dragging;
            } else if (my <= yt) {
                topy = 1;
                state = dragging;
            } else if (my >= yb) {
                bottomy = 1;
                state = dragging;
            }
        } else {
            KillEvent();
        }
    } else if (ev->ie_Class == RAWKEY) {
        KillEvent();
    }
    return ev;
}

struct InputEvent *Dragging(ev)
REGISTER struct InputEvent *ev;
{
    if (ev->ie_Class == IECLASS_RAWMOUSE) {
        if (ev->ie_Code == IECODE_NOBUTTON) {
              /* Skip consecutive move events */
            while (ev->ie_NextEvent &&
              (ev->ie_NextEvent->ie_Class == IECLASS_TIMER ||
               (ev->ie_NextEvent->ie_Class == IECLASS_RAWMOUSE &&
                ev->ie_NextEvent->ie_Code == IECODE_NOBUTTON))) {
                ev = ev->ie_NextEvent;
            }
            GetSMousePos();
            if (!leftx && mx <= xl) {
                if (rightx) {
                    xr = w->LeftEdge + w->Width - 1;
                    rightx = 0;
                }
                leftx = 1;
            }
            if (!rightx && mx >= xr) {
                if (leftx) {
                    xl = w->LeftEdge;
                    leftx = 0;
                }
                rightx = 1;
            }
            if (!topy && my <= yt) {
                if (bottomy) {
                    yb = w->TopEdge + w->Height - 1;
                    bottomy = 0;
                }
                topy = 1;
            }
            if (!bottomy && my >= yb) {
                if (topy) {
                    yt = w->TopEdge;
                    topy = 0;
                }
                bottomy = 1;
            }
            if (leftx) {
                xl = mx;
            } else if (rightx) {
                xr = mx;
            }
            if (topy) {
                yt = my;
            } else if (bottomy) {
                yb = my;
            }
            if (xr - xl < minx) {
                if (leftx) {
                    xl = xr - minx;
                } else if (rightx) {
                    xr = xl + minx;
                }
/*                leftx = rightx = 0; */
            }
            if (xr - xl > maxx) {
                if (leftx) {
                    xl = xr - maxx;
                } else if (rightx) {
                    xr = xl + maxx;
                }
/*                leftx = rightx = 0; */
            }
            if (yb - yt < miny) {
                if (topy) {
                    yt = yb - miny;
                } else if (bottomy) {
                    yb = yt + miny;
                }
/*                topy = bottomy = 0; */
            }
            if (yb - yt > maxy) {
                if (topy) {
                    yt = yb - maxy;
                } else if (bottomy) {
                    yb = yt + maxy;
                }
/*                topy = bottomy = 0; */
            }
            if (xl != oxl || xr != oxr || yt != oyt || yb != oyb) {
                BuildFrame(xl, yt, xr, yb);
                DrawFrame();
                oxl = xl;
                oxr = xr;
                oyt = yt;
                oyb = yb;
            }
        } else if (ev->ie_Code == IECODE_LBUTTON+IECODE_UP_PREFIX) {
            REGISTER WORD movex, movey;
            REGISTER WORD sizex, sizey;
            REGISTER WORD premovex, premovey;
            KillEvent();
            EraseFrame();
            UnlockLayers(LockedLayerInfo);
            movex = xl - w->LeftEdge;
            movey = yt - w->TopEdge;
            sizex = xr - (xl + w->Width - 1);
            sizey = yb - (yt + w->Height - 1);
            premovex = 0;
            premovey = 0;
            if (movex < 0) {
                premovex = movex;
                movex = 0;
            }
            if (movey < 0) {
                premovey = movey;
                movey = 0;
            }
            if (premovex || premovey) {
                MoveWindow(w, (LONG)premovex, (LONG)premovey);
            }
            if (sizex || sizey) {
                SizeWindow(w, (LONG)sizex, (LONG)sizey);
            }
            if (movex || movey) {
                MoveWindow(w, (LONG)movex, (LONG)movey);
            }
            state = waiting;
        } else if (ev->ie_Code == IECODE_RBUTTON) {
            KillEvent();
            leftx = rightx = topy = bottomy = 0;
            state = changing;
        } else {
            KillEvent();
        }
    } else if (ev->ie_Class == RAWKEY) {
        KillEvent();
    }
    return ev;
}

struct InputEvent *Changing(ev)
REGISTER struct InputEvent *ev;
{
    if (ev->ie_Class == IECLASS_RAWMOUSE) {
        if (ev->ie_Code == IECODE_LBUTTON+IECODE_UP_PREFIX) {
            KillEvent();
            EraseFrame();
            UnlockLayers(LockedLayerInfo);
            state = waiting;
        } else if (ev->ie_Code == IECODE_RBUTTON+IECODE_UP_PREFIX) {
            KillEvent();
            state = dragging;
        } else if (ev->ie_Code != IECODE_NOBUTTON) {
            KillEvent();
        }
    } else if (ev->ie_Class == RAWKEY) {
        KillEvent();
    }
    return ev;
}

struct InputEvent *CHandler(nm0, nm1, Events)
struct InputEvent *Events;
{
    REGISTER struct InputEvent *ev;

    geta4();

    for (ev = Events; ev; ev = ev->ie_NextEvent) {
        switch(state) {
            case waiting: {
                ev = Waiting(ev);
                break;
            }
            case startframe: {
                ev = StartFrame(ev);
                break;
            }
            case dragging: {
                ev = Dragging(ev);
                break;
            }
            case changing: {
                ev = Changing(ev);
                break;
            }
        }
    }
    return Events;
}

SetUpForFrame()
{
    xl = w->LeftEdge;
    xr = xl + w->Width - 1;
    yt = w->TopEdge;
    yb = yt + w->Height - 1;
    minx = (w->MinWidth > 70 ? w->MinWidth : 70);
    miny = (w->MinHeight > 20 ? w->MinHeight : 20);
    maxx = (w->MaxWidth < s->Width ? w->MaxWidth : s->Width);
    maxy = (w->MaxHeight < s->Height ? w->MaxHeight : s->Height);
    leftx = rightx = topy = bottomy = 0;
    BuildFrame(xl, yt, xr, yb);

      /* Lock everything - find out what happens */
    LockedLayerInfo = &s->LayerInfo;
    LockLayers(LockedLayerInfo);

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

    OF = 0;
    DrawFrame();
}
