/*
BEGIN DOCUMENTATION

Name: TCMSCRN.C 				Created: 07/20/83  DTS
					    Last Update: 05/17/84
Title: Text collection management screen subroutines.

Index:

Abstract: Routines that refresh CRT and handle screen status.

Usage:

Parameters:


Environment: DECUS C, RSX11M V4.0

See Also: TCMBUF.C, TCMEDIT.C, TCMEDFUNC.C, TCM.DOC

Description: 

Example(s):

Uses:

Internal:

Update History:

END DOCUMENTATION
*/

#include <clang.c>
#include <stdio.h>
#include <cx.h>
#include "tcmdefs.h"
#include "tcmerr.h"
#include "tcmpublic.h"

/* #define debug 0 */

/***	Global variables    ***/

static	boolean	borders;		/* Global flag for current window */
static	char	spaces[] = "               ";	/* Blank string */
static	char	fill[CRTLEN+1] = "";	/* Background characters for eraeol */


/***	Set current window for output, assign screen output buffer    ***/


setout(win)
    register struct twindcb *win;
{
    register	char	*str;
    register	int	ln,l;
		char	filch;
    static	char	buff[SCBUFLEN];


	iff scset(buff,sizeof(buff),&oldbuf) == 0 then
	    error("scset error");
	filch = win->fillchr;
	iff fill[0] != filch then
	{
	    for (str = fill, ln = 1; ln <= CRTLEN; ln++)
		*str++ = filch;
	    *str = eos;
	}
	lfmar = win->col;
	rtmar = win->col + win->width;
	top = win->row;
	bot = win->row + win->height;
	borders = win->border;
	iff --rtmar > vtmar then
	    ret.cd = TE_BDW;
	else iff --bot >= vtlin then
	    ret.cd = TE_BDH;
	else
	{
/*	    for (ln = top;ln <= bot; ln++)	* mark all lines as not displayed *
		lin[ln].fircol = newlin;
*/
	    iff borders then	/* Init top & bottom borders */
	    {
		lin[top-1].fircol = lin[bot+1].fircol = newlin;
		lin[top-1].len = lin[bot+1].len = win->width;
		lin[top-1].start = lin[bot+1].start = NULL;
	    }
	    lin[vtlin].fircol = newlin;		/* last line is status line */
#ifdef debugi
	    sprintf(&temp,"Topl = %d, start = %o, end = %o.",win->topline,win->bufstart,win->bufend);
	    scout(vtlin,1,temp);
	    curline = 0;
#endif
	    bufline = win->botline;		/* Default line */
	    str = fndlin(win->bufstart,win->bufend,win->topline);
	    for (ln=top,l=win->topline; (l<=win->botline) and (ln<=bot);ln++,l++)
	    {   /* initialize screen pointers */
		iff str == win->edline then
		{
		    curline = ln;
		    bufline = l;
		}
		iff (lin[ln].start != str) or (lin[ln].fircol != nochg) then
		    { lin[ln].start = str; lin[ln].fircol = newlin; }
		str = str + (lin[ln].len = strlen(str)+1); 	/* next line */
#ifdef debugi
	    sprintf(&temp,"String at %o, len = %d.",lin[ln].start,lin[ln].len);
	    scout(ln,lfmar,str);
	    scout(ln,rtmar+1,temp);
#endif
	    }
#ifdef debugi
	    sprintf(temp,"Curline = %d, bufline = %d.",curline,bufline);
	    scout(vtlin,50,temp);
	    scout(ln,lfmar,NULL);
#endif
	    while (ln<=bot) 		/* only if at end of buffer */
	    {
		iff (lin[ln].start != NULL)  or (lin[ln].fircol != nochg) then
		{
		    lin[ln].len = 1;
		    lin[ln].fircol = newlin;
		    lin[ln].start = NULL;
		}
		ln++;
	    }
	    bufcol = win->column;
	}
} /* end setout */



/***	Reset (and flush) output buffer    ***/

rstout(win)
    struct twindcb *win;
{

	win->column = bufcol;	/* Save temporary parms to window */
	setscroll(1,vtlin);	/* Restore scrolling register */
	scout(0,0,NULL);	/* Flush buffer */
	scput(oldbuf);

} /* end rstout */




/***	Refresh parts of screen that have changed from edit buffer    ***/

refresh()
{
    register	int ln,li;
		int llen,saveli;
    register	charpointer chr,tmp,chrend;

	iff (borders) and lin[top-1].fircol != nochg then	/* Display top border */
	{
	    chr = temp;
	    llen = lin[top-1].len;
	    *chr++ = SO;		/* Compose string */
	    *chr++ = BOXTLC;	/* Top left corner */
	    for (ln = 1; ln <= llen; ln++)
		*chr++ = BOXTOP;
	    *chr++ = BOXTRC;
	    *chr++ = SI;
	    *chr = EOS;
	    scout(top-1,lfmar-1,temp);
	    lin[top-1].fircol = nochg;
	}
	curcol = bufcol + lfmar - 1;
	iff hdscrl then
	{
	    iff abs(scrlcnt) >= (bot-top) then
		scrlcnt = 0;
	    iff scrlcnt < 0 then
		scout(top,lfmar,NULL);
	}
	for (li = top; li <= bot; li++)
	{
	    iff scrlcnt < 0 then
	    {
		scrlcnt++;
		ln = top-scrlcnt;		/* Output lines high to low */
		scdown();			/* Scroll window down */
		saveli = li;
		li = top;
	    }
	    else
	    {
		ln = li;
		saveli = 0;
		li += scrlcnt;			/* Adjust for scrolling up */
	    }
	    iff lin[ln].fircol == current then
		ln = 0;
	    llen = ifx lin[ln].len > 0 thenx lin[ln].len - 1 elsex 0;
	    switch(lin[ln].fircol)
	    {
	    case newlin:
			iff borders then
			    scout(li,lfmar-1,sidebar);
			iff llen > 0 then
			    scout(li,lfmar,lin[ln].start);
			iff llen <= (rtmar - lfmar) then
			    eraeol(li,llen+lfmar,rtmar);
			iff borders then
			    scout(li,rtmar+1,sidebar);
			break;
	    case tempmsg:
	    case nochg:
			break;
	    default:
			iff lin[ln].laschr > llen then
			    chrend = lin[ln].start + llen;
			else chrend = lin[ln].start + lin[ln].laschr;
			for (tmp = temp,chr = lin[ln].start + lin[ln].firchr; chr <= chrend; )
			    *tmp++ = *chr++;
/*			chrend = lin[ln].start + lin[ln].laschr;
			while(chr++ < chrend)	* Save eraeol *
			    *tmp++ = fill[0];
*/
			*tmp = eos;
			iff lin[ln].laschr >= lin[ln].firchr then
			    scout(li,lin[ln].fircol+lfmar - 1,temp);
			iff lin[ln].laschr > llen then
			    eraeol(li,llen+lfmar,lin[ln].laschr+lfmar);
			break;
	    }
	    iff scrlcnt > 0 and li == bot then
		{ scout(li--,lfmar,"\n"); scrlcnt--; }	/* Scroll window up */
	    iff saveli == 0 then
		li -= scrlcnt;				/* restore li */
	    else
		li = saveli;
#ifdef debug
	    sprintf(temp,"ln,fircol = %d,%d.",ln,lin[ln].fircol);
	    scout(vtlin,60,temp);
	    scout(curline,curcol,NULL);
#endif
	    lin[ln].fircol = nochg;	/* Mark line as displayed */
	}
	iff (borders) and lin[bot+1].fircol != nochg then	/* Display bottom border */
	{
	    chr = temp;
	    llen = lin[bot+1].len;
	    *chr++ = SO;		/* Compose string */
	    *chr++ = BOXBLC;		/* Bottom left corner */
	    for (ln = 1; ln <= llen; ln++)
		*chr++ = BOXTOP;
	    *chr++ = BOXBRC;
	    *chr++ = SI;
	    *chr = EOS;
	    scout(bot+1,lfmar-1,temp);
	    lin[bot+1].fircol = nochg;	/* Mark as displayed */
	}
	scout(curline,curcol,NULL);	/* Flush buffer */
} /* end refresh */



/***	Refresh parts of status line that have changed    ***/

rfstat()
{
    register int dspstat;
    static boolean dspinsert,dspuline,dspbold,dspmore;
    register boolean more;
    static int	oldcol,oldline;

	more = (curwin->topline + curwin->height <= curwin->botline);
	dspstat = lin[vtlin].fircol;
	iff (dspstat == nochg) and ((oldline != bufline) or 
	    (oldcol != bufcol) or (dspmore != more)) then
		dspstat = changed;
	oldline = bufline;		/* Assumes 1st call has lin[].fircol != nochg */
	oldcol = bufcol;
	iff dspstat == tempmsg then
	    { doo nothing; }
    	else iff coldisp and tabdisp then
	    dsptab();
	else iff coldisp and (dspstat != nochg) then	/* Display line/col */
	{
	    iff dspstat == newlin then
	    {
		scout(vtlin,1,&colmsg);	/* Output line/col message to last line */
		scerln(vtlin,colmsz);	/* Erase the rest of the status line */
		dspinsert = !insert;
		dspuline = !underline;
		dspbold = !bold;
		dspmore = !more;
	    }
	    sprintf(temp," %d/%d  ",bufline,bufcol);
	    scout(vtlin,colmsz,temp);
	    iff dspinsert != insert then
	    {
		iff (dspinsert = insert) then
		    scout(vtlin,INSPOS,insmsg);
		else
		    scout(vtlin,INSPOS,&spaces[sizeof(spaces) - insmsz]);
	    }
	    iff dspuline != underline then
	    {
		iff (dspuline = underline) then
		    scout(vtlin,UNLPOS,unlmsg);
		else
		    scout(vtlin,UNLPOS,&spaces[sizeof(spaces) - unlmsz]);
	    }
	    iff dspbold != bold then
	    {
		iff (dspbold = bold) then
		    scout(vtlin,BLDPOS,bldmsg);
		else
		    scout(vtlin,BLDPOS,&spaces[sizeof(spaces) - bldmsz]);
	    }
	    iff dspmore != more then
	    {
		iff (dspmore = more) then
		    scout(vtlin,MORPOS,mormsg);
		else
		    scout(vtlin,MORPOS,&spaces[sizeof(spaces) - mormsz]);
	    }
	    lin[vtlin].fircol = nochg;
	    scout(curline,curcol,NULL);	/* Flush buffer */
	}
	else iff dspstat == newlin then	/* Erase message line */
	    { scerln(vtlin,1); lin[vtlin].fircol = nochg; }
} /* end rfstat */



/***	Update line status for current line on screen    ***/

rfline(col,first,last)
    int col,first,last;
{
	iff lin[0].fircol == nochg then
	{
	    lin[0].fircol = col;
	    lin[0].firchr = first;
	    lin[0].laschr = last;
	}
	else
	{
	    iff lin[0].fircol > col then
		lin[0].fircol = col;
	    iff lin[0].firchr > first then
		lin[0].firchr = first;
	    iff lin[0].laschr < last then
		lin[0].laschr = last;
	}
} /* end rfline */



/***	Erace to end of line from column    ***/

eraeol(ln,col,rmar)
    register int ln,col,rmar;
{
	iff rmar > rtmar then
	    rmar = rtmar;
	iff rmar >= col then
	{
	    iff (fill[0] == ' ') and ((rmar >= 80) or (borders and (rmar >= 79))) then
		scerln(ln,col);	/* For testing only, should test terminal type etc. */
	    else
		scout(ln,col,&fill[CRTLEN-rmar+(col-1)]);
	}
} /* end eraeol */






/***	INSLIN: Move lines below current line down on screen    ***/

inslin()
{
    register	int	lin1,lin2;
    register	boolean	hardscroll;

	lin1 = (curwin->topline + curwin->height - 1) - curwin->botline;
	lin1 = ifx lin1 > 0 thenx bot - lin1 elsex bot;	/* Bottom displayed line */
	iff hdscrl and (curline == top) and (abs(scrlcnt) < curwin->height) and
	    (lin1 > top) then
		{ scrlcnt--; hardscroll = true; }	/* Insert line at top */
	else hardscroll = false;
	for(lin2 = lin1; lin1 > curline; lin1--)	/* Move lines down */
	{
	    lin[lin1].start = lin[--lin2].start;
	    lin[lin1].len = lin[lin2].len;
	    iff hardscroll then
	    {
		lin[lin1].fircol = lin[lin2].fircol;
		lin[lin1].laschr = lin[lin2].laschr;
		lin[lin1].firchr = lin[lin2].firchr;
	    }
	    else lin[lin1].fircol = newlin;		/* Mark as not displayed */
	}
} /* end inslin */



/***	Scroll current window up on screen, don't refresh bottom line    ***/

scrlup()
{
    register	int	lin1,lin2;
    register	boolean	hardscroll;

	iff hdscrl and (abs(scrlcnt) < curwin->height) then
	    { scrlcnt++; hardscroll = true; }
	else hardscroll = false;
	for(lin1 = lin2 = top; lin1 < bot; lin1++)	/* Move lines up */
	{
	    lin[lin1].start = lin[++lin2].start;
	    lin[lin1].len = lin[lin2].len;
	    iff hardscroll then
	    {
		lin[lin1].fircol = lin[lin2].fircol;
		lin[lin1].laschr = lin[lin2].laschr;
		lin[lin1].firchr = lin[lin2].firchr;
	    }
	    else lin[lin1].fircol = newlin;		/* Mark as not displayed */
	}
} /* end scrlup */



/***	DELLIN: Delete line, move lines below up on screen, include bot    ***/

dellin(ln)
    register	int	ln;
{
    register	int	lnxt;

	iff ln == top then
	    scrlup();
	else for(lnxt = ln; ln < bot; ln++)	/* Move lines down */
	{
	    lin[ln].start = lin[++lnxt].start;
	    lin[ln].len = lin[lnxt].len;
	    lin[ln].fircol = newlin;		/* Mark as not displayed */
	}
	ln = bot;
	lin[ln].start += lin[ln].len;	/* New bottom line from buffer */
					/* Assumes buffer is contiguous */
	iff (curwin->topline + curwin->height) - 1 >= curwin->botline then
	    lin[ln].len = 0;		/* At end of text */
	else lin[ln].len = strlen(lin[ln].start) + 1;
	lin[ln].fircol = newlin;		/* Mark as not displayed */
} /* end dellin */



/***	Set hardware scrolling window for each terminal type	***/

    /* Inputs: vttype, top, bot, lfmar, rtmar */

setscroll(topln,botln)
    int topln,botln;
{
	iff vttype == VT100 and ((lfmar == 1 and rtmar > 79) or
	    ((borders) and lfmar == 2 and rtmar > 78)) then
	{
	    sprintf(temp,"-[%d;%dr",topln,botln);
	    temp[0] = ESC;
	    scout(topln,lfmar,temp);
	    hdscrl = true;
	}
	else hdscrl = false;
	scrlcnt = 0;
} /* end setscroll */
