
/*
 * HOUSEKEEPING.C
 * (c) 1992 J.Harper
 */

#include "jed.h"
#include "jed_protos.h"

Prototype   VOID    keepposaddx		(WORD);
Prototype   VOID    keeppossubx		(WORD);
Prototype   VOID    keepposaddy		(LONG);
Prototype   VOID    keeppossuby		(LONG);
Prototype   VOID    keeppossplity	(VOID);
Prototype   VOID    keepposjoiny	(VOID);
Prototype   VOID    resyncx		(VOID);
Prototype   VOID    resyncy		(VOID);
Prototype   VOID    resyncxy		(VOID);
Prototype   VOID    resetallviews	(TX *);
Local	    VOID    scrollvwup		(VOID);
Local	    VOID    scrollvwdn		(VOID);

/*
 * The next few routines deal with updating the various references to
 * coordinates throughout the views after chunks have been deleted and
 * inserted.
 */
VOID
keepposaddx(WORD addx)
{
    TX *tx = CurrVW->vw_Tx;
    VW *thisvw;
    MARK *thismark;
    WORD xpos = CurrVW->vw_CursorPos.pos_Col;
    LONG ypos = CurrVW->vw_CursorPos.pos_Line;

#define upd(x,y) if((y == ypos) && (x >= xpos)) x += addx

    for(thisvw = (VW *)tx->tx_Views.mlh_Head; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
    {
	upd(thisvw->vw_CursorPos.pos_Col, thisvw->vw_CursorPos.pos_Line);
	upd(thisvw->vw_AutoMark.pos_Col, thisvw->vw_AutoMark.pos_Line);
	upd(thisvw->vw_Block[0].pos_Col, thisvw->vw_Block[0].pos_Line);
	upd(thisvw->vw_Block[1].pos_Col, thisvw->vw_Block[1].pos_Line);
    }
    for(thismark = (MARK *)tx->tx_Marks.mlh_Head; thismark->mk_Node.mln_Succ; thismark = (MARK *)thismark->mk_Node.mln_Succ)
    {
	upd(thismark->mk_Pos.pos_Col, thismark->mk_Pos.pos_Line);
    }

#undef upd(x,y)
}

VOID
keeppossubx(WORD subx)
{
    TX *tx = CurrVW->vw_Tx;
    VW *thisvw;
    MARK *thismark;
    WORD xpos = CurrVW->vw_CursorPos.pos_Col;
    LONG ypos = CurrVW->vw_CursorPos.pos_Line;

#define upd(x,y) if((y == ypos) && (x >= xpos)) { if((x -= subx) < xpos) x = xpos; }

    for(thisvw = (VW *)tx->tx_Views.mlh_Head; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
    {
	upd(thisvw->vw_CursorPos.pos_Col, thisvw->vw_CursorPos.pos_Line);
	upd(thisvw->vw_AutoMark.pos_Col, thisvw->vw_AutoMark.pos_Line);
	upd(thisvw->vw_Block[0].pos_Col, thisvw->vw_Block[0].pos_Line);
	upd(thisvw->vw_Block[1].pos_Col, thisvw->vw_Block[1].pos_Line);
    }
    for(thismark = (MARK *)tx->tx_Marks.mlh_Head; thismark->mk_Node.mln_Succ; thismark = (MARK *)thismark->mk_Node.mln_Succ)
    {
	upd(thismark->mk_Pos.pos_Col, thismark->mk_Pos.pos_Line);
    }

#undef upd(x,y)
}

/*
 * Whole lines only please
 */
VOID
keepposaddy(LONG addy)
{
    TX *tx = CurrVW->vw_Tx;
    VW *thisvw;
    MARK *thismark;
    LONG ypos = CurrVW->vw_CursorPos.pos_Line;

#define upd(y) if(y >= ypos) y += addy

    for(thisvw = (VW *)tx->tx_Views.mlh_Head; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
    {
	upd(thisvw->vw_CursorPos.pos_Line);
	upd(thisvw->vw_AutoMark.pos_Line);
	upd(thisvw->vw_Block[0].pos_Line);
	upd(thisvw->vw_Block[1].pos_Line);
	if(thisvw != CurrVW)
	{
	    upd(thisvw->vw_StartLine);
	}
    }
    for(thismark = (MARK *)tx->tx_Marks.mlh_Head; thismark->mk_Node.mln_Succ; thismark = (MARK *)thismark->mk_Node.mln_Succ)
    {
	upd(thismark->mk_Pos.pos_Line);
    }

#undef upd(y)
}

/*
 * Whole lines only please
 */
VOID
keeppossuby(LONG suby)
{
    TX *tx = CurrVW->vw_Tx;
    VW *thisvw;
    MARK *thismark;
    LONG ypos = CurrVW->vw_CursorPos.pos_Line;

#define upd(y) if(y > ypos) { if((y -= suby) < ypos) y = ypos; }
#define upd2(x,y) if(y >= ypos) { if((y -= suby) < ypos) {y = ypos; x = 0; }}

    for(thisvw = (VW *)tx->tx_Views.mlh_Head; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
    {
	upd2(thisvw->vw_CursorPos.pos_Col, thisvw->vw_CursorPos.pos_Line);
	upd2(thisvw->vw_CursorPos.pos_Col, thisvw->vw_AutoMark.pos_Line);
	upd2(thisvw->vw_Block[0].pos_Col, thisvw->vw_Block[0].pos_Line);
	upd2(thisvw->vw_Block[1].pos_Col, thisvw->vw_Block[1].pos_Line);
	if(thisvw != CurrVW)
	{
	    upd(thisvw->vw_StartLine);
	}
    }
    for(thismark = (MARK *)tx->tx_Marks.mlh_Head; thismark->mk_Node.mln_Succ; thismark = (MARK *)thismark->mk_Node.mln_Succ)
    {
	upd2(thismark->mk_Pos.pos_Col, thismark->mk_Pos.pos_Line);
    }

#undef upd(y)
#undef upd2(x,y)
}

/*
 * Use when splitting a line into 2, cursor should be at position of split
 */
VOID
keeppossplity(VOID)
{
    TX *tx = CurrVW->vw_Tx;
    VW *thisvw;
    MARK *thismark;
    WORD xpos = CurrVW->vw_CursorPos.pos_Col;
    LONG ypos = CurrVW->vw_CursorPos.pos_Line;

#define upd(y) if(y > ypos) y++
#define upd2(x,y) if((y == ypos) && (x >= xpos)) { x -= xpos; y++; } else if(y > ypos) y++

    for(thisvw = (VW *)tx->tx_Views.mlh_Head; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
    {
	upd2(thisvw->vw_CursorPos.pos_Col, thisvw->vw_CursorPos.pos_Line);
	upd2(thisvw->vw_AutoMark.pos_Col, thisvw->vw_AutoMark.pos_Line);
	upd2(thisvw->vw_Block[0].pos_Col, thisvw->vw_Block[0].pos_Line);
	upd2(thisvw->vw_Block[1].pos_Col, thisvw->vw_Block[1].pos_Line);
	if(thisvw != CurrVW)
	{
	    upd(thisvw->vw_StartLine);
	}
    }
    for(thismark = (MARK *)tx->tx_Marks.mlh_Head; thismark->mk_Node.mln_Succ; thismark = (MARK *)thismark->mk_Node.mln_Succ)
    {
	upd2(thismark->mk_Pos.pos_Col, thismark->mk_Pos.pos_Line);
    }

#undef upd(y)
#undef upd2(x,y)
}

/*
 * Use when compacting 2 adjacent lines into one
 */
VOID
keepposjoiny(VOID)
{
    VW *thisvw = CurrVW;
    TX *tx = thisvw->vw_Tx;
    MARK *thismark;
    LONG ypos = thisvw->vw_CursorPos.pos_Line;
    WORD xpos = thisvw->vw_CursorPos.pos_Col;

#define upd(y) if(y > ypos) y--
#define upd2(x,y) if(y > ypos) { if(y == ypos + 1) x += xpos; y--; }

    for(thisvw = (VW *)tx->tx_Views.mlh_Head; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
    {
	upd2(thisvw->vw_CursorPos.pos_Col, thisvw->vw_CursorPos.pos_Line);
	upd2(thisvw->vw_AutoMark.pos_Col, thisvw->vw_AutoMark.pos_Line);
	upd2(thisvw->vw_Block[0].pos_Col, thisvw->vw_Block[0].pos_Line);
	upd2(thisvw->vw_Block[1].pos_Col, thisvw->vw_Block[1].pos_Line);
	if(thisvw != CurrVW)
	{
	    upd(thisvw->vw_StartLine);
	}
    }
    for(thismark = (MARK *)tx->tx_Marks.mlh_Head; thismark->mk_Node.mln_Succ; thismark = (MARK *)thismark->mk_Node.mln_Succ)
    {
	upd2(thismark->mk_Pos.pos_Col, thismark->mk_Pos.pos_Line);
    }

#undef upd(y)
#undef upd2(x,y)
}

/*
 * These routines are called to recalculate the cursor's position on the
 * screen, they handle all scrolling (vertical and horizontal)
 *
 * refresh() should be called after any of these functions.
 */
VOID
resyncx(VOID)
{
    VW *vw = CurrVW;

    while((vw->vw_CursorPos.pos_Col - vw->vw_StartCol) >= vw->vw_MaxX)
    {
	vw->vw_StartCol += vw->vw_XStep;
	vw->vw_RefreshType |= RFF_ALL;
    }
    while(vw->vw_CursorPos.pos_Col < vw->vw_StartCol)
    {
	vw->vw_StartCol -= vw->vw_XStep;
	if(vw->vw_StartCol < 0)
	    vw->vw_StartCol = 0;
	vw->vw_RefreshType |= RFF_ALL;
    }
}

VOID
resyncy(VOID)
{
    VW *vw = CurrVW;
    WORD y = vw->vw_CursorPos.pos_Line - vw->vw_StartLine;

    if(y < 0)
    {
	if((y == -1) && (!(vw->vw_RefreshType & RFF_ALL)) && (!vw->vw_Sleeping) && (!vw->vw_DisplayLock))
	{
	    LINE *newline = vw->vw_Tx->tx_Lines + vw->vw_CursorPos.pos_Line;
	    scrollvwdn();
	    pentoline(0);
	    drawline(newline, vw->vw_CursorPos.pos_Line);
	}
	else
	    vw->vw_RefreshType |= RFF_ALL;
	vw->vw_StartLine = vw->vw_CursorPos.pos_Line;
    }
    else if(y >= vw->vw_MaxY)
    {
	if((y == vw->vw_MaxY) && (!(vw->vw_RefreshType & RFF_ALL)) && (!vw->vw_Sleeping) && (!vw->vw_DisplayLock))
	{
	    LINE *newline = vw->vw_Tx->tx_Lines + vw->vw_CursorPos.pos_Line;
	    scrollvwup();
	    pentoline(vw->vw_MaxY - 1);
	    drawline(newline, vw->vw_CursorPos.pos_Line);
	}
	else
	    vw->vw_RefreshType |= RFF_ALL;
	vw->vw_StartLine = vw->vw_CursorPos.pos_Line - vw->vw_MaxY + 1;
    }
}

VOID
resyncxy(VOID)
{
    VW *vw = CurrVW;
    WORD y = vw->vw_CursorPos.pos_Line - vw->vw_StartLine;

    while((vw->vw_CursorPos.pos_Col - vw->vw_StartCol) >= vw->vw_MaxX)
    {
	vw->vw_StartCol += vw->vw_XStep;
	vw->vw_RefreshType |= RFF_ALL;
    }
    while(vw->vw_CursorPos.pos_Col < vw->vw_StartCol)
    {
	vw->vw_StartCol -= vw->vw_XStep;
	if(vw->vw_StartCol < 0)
	    vw->vw_StartCol = 0;
	vw->vw_RefreshType |= RFF_ALL;
    }
    if(y < 0)
    {
	if((y == -1) && (!(vw->vw_RefreshType & RFF_ALL)) && (!vw->vw_Sleeping) && (!vw->vw_DisplayLock))
	{
	    LINE *newline = vw->vw_Tx->tx_Lines + vw->vw_CursorPos.pos_Line;
	    scrollvwdn();
	    pentoline(0);
	    drawline(newline, vw->vw_CursorPos.pos_Line);
	}
	else
	    vw->vw_RefreshType |= RFF_ALL;
	vw->vw_StartLine = vw->vw_CursorPos.pos_Line;
    }
    else if(y >= vw->vw_MaxY)
    {
	if((y == vw->vw_MaxY) && (!(vw->vw_RefreshType & RFF_ALL)) && (!vw->vw_Sleeping) && (!vw->vw_DisplayLock))
	{
	    LINE *newline = vw->vw_Tx->tx_Lines + vw->vw_CursorPos.pos_Line;
	    scrollvwup();
	    pentoline(vw->vw_MaxY - 1);
	    drawline(newline, vw->vw_CursorPos.pos_Line);
	}
	else
	    vw->vw_RefreshType |= RFF_ALL;
	vw->vw_StartLine = vw->vw_CursorPos.pos_Line - vw->vw_MaxY + 1;
    }
}

/*
 * This makes all views of this file have their cursor at the top of the
 * file, it also refreshes each view.
 */
VOID
resetallviews(TX *tx)
{
    VW *thisvw;
    VW *currvw = CurrVW;
    for(thisvw = (VW *)tx->tx_Views.mlh_Head; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
    {
	thisvw->vw_CursorPos.pos_Col = 0;
	thisvw->vw_CursorPos.pos_Line = 0;
	thisvw->vw_StartCol = 0;
	thisvw->vw_StartLine = 0;
	thisvw->vw_AutoMark.pos_Col = 0;
	thisvw->vw_AutoMark.pos_Line = 0;
	thisvw->vw_BlockStatus = -1;
	thisvw->vw_RefreshType |= RFF_ALL;
	thisvw->vw_NonStdTitle = FALSE;
	CurrVW = thisvw;
	stdtitle();
    }
    CurrVW = currvw;
    refreshallviews(tx);
}

/*
 * Scrolls the view one line,
 * if there is no block markings on this page a new BitMap is faked --
 * with a depth of 1, this (almost) doubles scrolling speed, thanks to
 * Adriaan van den Brand for this cool idea.
 */
VOID
scrollvwup(VOID)
{
    VW *vw = CurrVW;
    struct RastPort *rp = vw->vw_Rp;
    if(ScrollHack)
    {
	struct BitMap *oldbm = rp->BitMap;
	struct BitMap newbm = *oldbm;
	newbm.Depth = pageinblock() ? 2 : 1;
	rp->BitMap = &newbm;
	ScrollRaster(rp, 0, vw->vw_FontY, vw->vw_XStartPix, vw->vw_YStartPix, vw->vw_XEndPix, vw->vw_YStartPix + (vw->vw_MaxY * vw->vw_FontY) - 1);
	rp->BitMap = oldbm;
    }
    else
	ScrollRaster(rp, 0, vw->vw_FontY, vw->vw_XStartPix, vw->vw_YStartPix, vw->vw_XEndPix, vw->vw_YStartPix + (vw->vw_MaxY * vw->vw_FontY) - 1);
}
VOID
scrollvwdn(VOID)
{
    VW *vw = CurrVW;
    struct RastPort *rp = vw->vw_Rp;
    if(ScrollHack)
    {
	struct BitMap *oldbm = rp->BitMap;
	struct BitMap newbm = *oldbm;
	newbm.Depth = pageinblock() ? 2 : 1;
	rp->BitMap = &newbm;
	ScrollRaster(rp, 0, -vw->vw_FontY, vw->vw_XStartPix, vw->vw_YStartPix, vw->vw_XEndPix, vw->vw_YStartPix + (vw->vw_MaxY * vw->vw_FontY) - 1);
	rp->BitMap = oldbm;
    }
    else
	ScrollRaster(rp, 0, -vw->vw_FontY, vw->vw_XStartPix, vw->vw_YStartPix, vw->vw_XEndPix, vw->vw_YStartPix + (vw->vw_MaxY * vw->vw_FontY) - 1);
}

