/*->c.vtwimp */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"
#include "h.bbc"
#include "h.flex"


#include "h.wos"
#include "h.main"
#include "h.ram"
#include "h.file"
#include "h.mym"
#include "h.pr"




#include "h.vtasm"

#include "h.term"

#include "h.vxdef"
#include "h.vxwimp"

#include "h.tek"

#include "h.vtlo"
#include "h.vtdef"
#include "h.vtscr"
#include "h.vtcol"
#include "h.vtkey"
#include "h.vtselect"

#include "h.vtwimp"




/***************************************************************************/
/*
 Code to handle terminal sprite
*/
/*****************************************************************************/


char * tsprite=NULL;

int usemode;

int notrans;          /* don't have to scale/col trans when plotting sprite */

sprite_factors  * scalefactors;
sprite_factors    scaleblock;
sprite_pixtrans * pixtrans;
char              pixtable[16];

int *             cachedata;     /* used to cache sprite contents */
int               cachexhilo;



char chars00[640*12];   /* buffer to hold mode  0 characters */
char chars18[640*20];   /* buffer to hold mode 18 characters */


int loadcharfile(char * name,char * dest,int height,int size)
{
 FILE        * fp;
 sprite_area   spa;
 sprite_header sphdr;
 int           i;
 int           j;
 int           word;
 char          filename[128];
 int           spare;

 if(height & 0x3) spare=4-(height & 0x3);
 else             spare=0;


 sprintf(filename,"%s.%s",path(HSYRD),name);

 fp=fopen(filename,"rb");
 if(fp)
 {
  fread((char*)(&spa)+4,1,sizeof(sprite_area)-4,fp);

  for(i=0;i<size;i++)
  {
   fread(&sphdr,1,sizeof(sprite_header),fp);
   for(j=0;j<height;j++)
   {
    fread(&word,1,sizeof(int),fp);
    *dest++=(char)word;
   }
   dest+=spare;
  }

  fclose(fp);
  return(1);
 }
 return(0);
}



/* clears a character defintition */

void vtclearchar(int cn)
{
 int * q;
 int    i;

 q=(int*)&chars00[cn*12];
 for(i=0;i<3;i++) *q++=0;

 q=(int*)&chars18[cn*20];
 for(i=0;i<5;i++) *q++=0;

}


/* defines a character                                     */
/* p points at 10 bytes arranged as rows across character */

void vtdefinechar(char * p,int cn)
{
 char * q;
 char * p2;
 int    i;

 p2=p;
 q=&chars00[cn*12];
 for(i=0;i<10;i++) *q++=*p++;

 p=p2;
 q=&chars18[cn*20];
 for(i=0;i<10;i++)
 {
  if(i!=0 && i!=9) *q++=*p;
  *q++=*p++;
 }
}



/*****************************************************************************/

void vtsetcharsize(void)
{
 vtoscharx=((TTBDX*vtzoom.mul)/vtzoom.div) & maskx;
 if(vtoscharx<2*deltax) vtoscharx=2*deltax;
 vtoschary=((TTBDY*vtzoom.mul)/vtzoom.div) & masky;
 if(vtoschary<2*deltay) vtoschary=2*deltay;
}




void createtermsprite(void)
{
 int       size;
 int       swidth;
 int       sheight;
 int       mustscalex=0;
 int       mustscaley=0;
 int       mustcoltrans=0;
 int       spln2bpp;

 notrans=1;
 pixtrans=(sprite_pixtrans *)(-1);
 scalefactors=NULL;
 cachedata=NULL;

 if(vtopen)
 {
  /* sort things out from mode etc. */

  size=sizeof(sprite_area)+sizeof(sprite_header);

  if(gcharsizey==16) sheight=18;
  else 
  {
   if(gcharsizey!=8) mustscaley=1;
   sheight=9;
  }

  if(gcharsizex!=8) mustscalex=1;

  spln2bpp=ln2bpp;

  if(ln2bpp==5)
  {
   swidth=32*width;
   if(gcharsizey==16) usemode=MX329090;
   else               usemode=MX329045;
  }
  else
  if(ln2bpp==4)
  {
   swidth=16*width;
   if(gcharsizey==16) usemode=MX169090;
   else               usemode=MX169045;
  }
  else
  if(ln2bpp==3)
  {
   swidth=8*width;
   if(gcharsizey==16) usemode=21;
   else               usemode=15;
  }
  else
  {
   if(ln2bpp!=2)      
   {
    mustcoltrans=1;
    spln2bpp=2;
   }
   swidth=4*width;
   if(gcharsizey==16) usemode=20;
   else               usemode=12;
  }

  size+=swidth*sheight;

  if(tsprite) flex_extend((flex_ptr)&tsprite,size);
  else        flex_alloc((flex_ptr)&tsprite,size);

  sprite_area_initialise((sprite_area *)tsprite,size);

  /* up to here, swidth is bytes, in the line below it is pixels */

  swidth=(swidth*8)/(1<<spln2bpp);

/*  if(usemode>MXNEWMODE)
  {
   int modespec[6];

   modespec[0]=1;
   modespec[1]=screenx;
   modespec[2]=screeny;
   modespec[3]=ln2bpp;
   modespec[4]=-1;
   modespec[5]=-1;

   report(sprite_create((sprite_area *)tsprite,"TERMSP",0,
                                              swidth,sheight,(int)modespec));
  }
  else */
  report(sprite_create((sprite_area *)tsprite,"TERMSP",0,
                                              swidth,sheight,usemode));

  if(mustscalex || mustscaley)
  {
   scalefactors=&scaleblock;

   if(mustscalex)
   {
    scalefactors->xmag=gcharsizex;
    scalefactors->xdiv=8;
   }
   else
   {
    scalefactors->xmag=1;
    scalefactors->xdiv=1;
   }

   if(mustscaley)
   {
    scalefactors->ymag=gcharsizey;
    scalefactors->ydiv=8;
   }
   else
   {
    scalefactors->ymag=1;
    scalefactors->ydiv=1;
   }
   notrans=0;
  }

  if(mustcoltrans)
  {
   wimp_palettestr wpal;
   wimp_readpalette(&wpal);
   selecttable(usemode,(int*)&wpal,-1,(int*)-1,pixtable);
   pixtrans=pixtable;
   notrans=0;
  }

  vtsetcharsize();

  if(vtzoom.mul!=vtzoom.div)
  {
   notrans=0;

   if(!scalefactors)
   {
    scalefactors=&scaleblock;
    scaleblock.xmag=TTDX;
    scaleblock.xdiv=TTBDX;
    scaleblock.ymag=TTDY;
    scaleblock.ydiv=TTBDY;
   }
   else
   {
    scaleblock.xmag*=TTDX;
    scaleblock.xdiv*=TTBDX;
    scaleblock.ymag*=TTDY;
    scaleblock.ydiv*=TTBDY;
   }
  }
/*  else
  {
   vtoscharx=TTBDX;
   vtoschary=TTBDY;
  } */
 }
}


void trashtermsprite(void)
{
 if(tsprite)
   flex_free((flex_ptr)&tsprite);
}




void vtinit(void)
{
 initscr();

 loadcharfile("C_VT00",&chars00[0],9,256);
 loadcharfile("C_ANSI00",&chars00[256*12],9,256);
 loadcharfile("C_VTX00",&chars00[512*12],9,128);
 loadcharfile("C_VT18",&chars18[0],18,256);
 loadcharfile("C_ANSI18",&chars18[256*20],18,256);
 loadcharfile("C_VTX18",&chars18[512*20],18,128);

 vtinitboot();
}


/*****************************************************************************/
/* save screen as sprite */

int vtsavescreensp(char * filename)
{
 FILE * fp;

 sprite_area   spa;
 sprite_header sph;
 int           palsize;
 int           y;
 int           yb;
 int   *       data;
 int           spwidth;
 tline *       lp;
 int           attr;
 int           xhilo;

 sprite_header  *  tspa=(sprite_header*)
                           (tsprite+(((sprite_area *)tsprite)->sproff));
 char           *  image=((char*)tspa)+tspa->image;
 sprite_id         spid;

 cachedata=NULL;


 /* wimp_palettestr wpal; */


 if((fp=ropen(filename,"wb"))==NULL) return(0);

 spa.number=1;
 spa.sproff=sizeof(sprite_area);

/* palsize=16*2*sizeof(int); */
 palsize=0;

 sph.mode=usemode;
 sph.image=sizeof(sprite_header)+palsize;
 sph.mask=sph.image;
 memset(sph.name,0,12);
 strcpy(sph.name,"screen");

 switch(usemode)
 {
  case  12:
           sph.height=24*9-1;
           sph.width=width-1;
           break;

  case  15:
           sph.height=24*9-1;
           sph.width=width*2-1;
           break;

  case  20:
           sph.height=24*18-1;
           sph.width=width-1;
           break;

  case  21:
           sph.height=24*18-1;
           sph.width=width*2-1;
           break;


  case MX169090:
                sph.height=24*18-1;
                sph.width=width*4-1;
                break;

  case MX169045:
                sph.height=24*9-1;
                sph.width=width*4-1;
                break;

  case MX329090:
                sph.height=24*18-1;
                sph.width=width*8-1;
                break;

  case MX329045:
                sph.height=24*9-1;
                sph.width=width*8-1;
                break;

 }

 sph.lbit=0;
 sph.rbit=31;

 sph.next=sph.image+(sph.height+1)*(sph.width+1)*sizeof(int);
 spa.freeoff=sph.next+sizeof(sprite_area);

 rwrite(&spa.number,sizeof(sprite_area)-sizeof(int),1,fp);
 rwrite(&sph,sizeof(sprite_header),1,fp);

/*
 wimp_readpalette(&wpal);

 for(y=0;y<16;y++)
 {
  wpal.c[y].bytes.gcol=0;
  rwrite(&wpal.c[y],sizeof(int),1,fp);
  rwrite(&wpal.c[y],sizeof(int),1,fp);
 }
 */

 spid.tag=sprite_id_addr;
 spid.s.addr=tspa;


 for(y=0;y<24;y++)
 {
  yb=lineno(y);
  lp=(tline*)(lineindex+sizeof(tline)*yb);

  data=((int*)(linedata+lp->loc));
  attr=lp->attr;

  xhilo=width;


  if(usemode==MX329090 || usemode==MX329045) xhilo*=8;
  else
  if(usemode==MX169090 || usemode==MX169045) xhilo*=4;
  else
  if(usemode==15 || usemode==21) xhilo*=2;


  tspa->width=xhilo-1;
  spwidth=xhilo*4;

  if(vtinvert) vtinvertline(data);


  if(usemode>MXNEWMODE)
  {
   if(usemode==MX329090)
   {
    if(attr==VTASW)  line329090S(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADW)  line329090D(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHT) line329090DT(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHB) line329090DB(&data[0],image,xhilo,spwidth);
   }
   else
   if(usemode==MX329045)
   {
    if(attr==VTASW)  line329045S(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADW)  line329045D(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHT) line329045DT(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHB) line329045DB(&data[0],image,xhilo,spwidth);
   }
   else
   if(usemode==MX169090)
   {
    if(attr==VTASW)  line169090S(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADW)  line169090D(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHT) line169090DT(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHB) line169090DB(&data[0],image,xhilo,spwidth);
   }
   else
   if(usemode==MX169045)
   {
    if(attr==VTASW)  line169045S(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADW)  line169045D(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHT) line169045DT(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHB) line169045DB(&data[0],image,xhilo,spwidth);
   }
  }
  else
  if(usemode>15)
  {
   if(usemode==20)
   {
    if(attr==VTASW) line18S(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADW) line18D(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHT) line18DT(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHB) line18DB(&data[0],image,xhilo,spwidth);
   }
   else
   {
    if(attr==VTASW) line23S(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADW) line23D(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHT) line23DT(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHB) line23DB(&data[0],image,xhilo,spwidth);
   }
  }
  else
  {
   if(usemode==12)
   {
    if(attr==VTASW) line00S(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADW) line00D(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHT) line00DT(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHB) line00DB(&data[0],image,xhilo,spwidth);
   }
   else
   {
    if(attr==VTASW) line15S(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADW) line15D(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHT) line15DT(&data[0],image,xhilo,spwidth);
    else
    if(attr==VTADHB) line15DB(&data[0],image,xhilo,spwidth);
   }
  }
  
  /* save data */

  rwrite(image,(tspa->height+1)*(tspa->width+1)*sizeof(int),1,fp);

  if(vtinvert) vtinvertline(data);
 }

 savetypeclose(fp,filename);
 return(1);
}



/***************************************************************************/
/*
 Code to handle VT wimp interface
*/
/*****************************************************************************/


#define NLINE 0x0
#define RDATA 0x1
#define RDRAW 0x2

void redrawvtsub(wimp_redrawstr * redrawstr,int more,int flags,int shift)
{
 int ox;
 int oy;
 int xlo;
 int xhi;
 int ylo;
 int yhi;
 int y;
 int * data;
 int temp;
 int xhilo;
 int xplot;
 int yplot;
 int spwidth;
 tline * lp;
 int     attr;
 int     oldattr;
 int     yc=ttyy+tops;
 int     atrf=-1;
 int     oldrlo;
 int     oldrhi;
/* int     ystat; */

 sprite_header  *  tspa=(sprite_header*)
                           (tsprite+(((sprite_area *)tsprite)->sproff));
 char           *  image=((char*)tspa)+tspa->image;
 sprite_id spid;

/* if(vtheight==25 && vtstatus==VTSTLOCAL && !scalefactors) ystat=lineno(24);
 else                                                     ystat=-1; */


 if(!notrans && pixtrans==(sprite_pixtrans*)pixtable)
 {
  wimp_palettestr wpal;
  wimp_readpalette(&wpal);
  selecttable(usemode,(int*)&wpal,-1,(int*)-1,pixtable);
 }


 while(more)
 {
  ox=redrawstr->box.x0-redrawstr->scx;
  oy=redrawstr->box.y1-tscrolly-shift;

  spid.tag=sprite_id_addr;
  spid.s.addr=tspa;

  oldattr=-1;
  oldrlo=oldrhi=0;

  ylo=((oy-redrawstr->g.y1)/TTDY);

  temp=oy-redrawstr->g.y0;
  yhi=temp/TTDY;
  if(yhi*TTDY!=temp) yhi++;

  yplot=oy-ylo*TTDY;


  for(y=ylo;y<yhi;y++)
  {
   if(y>=buffsize) break;


   yplot-=TTDY;
   lp=vtindex(y);
   data=((int*)(linedata+lp->loc));
   attr=lp->attr;

   if(flags==RDATA)
   {                                
    if(lp->rlo==lp->rhi) continue;  /* !!!!! be careful */

    if(lp->rlo!=oldrlo || lp->rhi!=oldrhi)
    {
     oldrlo=lp->rlo;
     oldrhi=lp->rhi;
     oldattr=-1;
    }
   }
   else
   if(flags==NLINE) lp->rlo=lp->rhi=0;


   if(attr && oldattr<=0)
   {
    xlo=(redrawstr->g.x0-ox)/(2*TTDX);  /* >>5; */

    temp=redrawstr->g.x1-ox;
    xhi=temp/(2*TTDX); /* >>5; */
    if((xhi*2*TTDX)!=temp) xhi++;

    if(xhi>(width/2)) xhi=width/2;


    if(flags==RDATA)
    {
     if(xlo<oldrlo) xlo=oldrlo;
     if(xhi>oldrhi) xhi=oldrhi;
    }

    xhilo=2*(xhi-xlo);

    if(usemode==15 || usemode==21) xhilo*=2;
    else
    if(usemode==MX169090 || usemode==MX169045) xhilo*=4;
    else
    if(usemode==MX329090 || usemode==MX329045) xhilo*=8;

    tspa->width=xhilo-1;
    spwidth=xhilo*4;

    xplot=ox+xlo*2*TTDX;
   }
   else
   if(!attr && oldattr)
   {
    xlo=(redrawstr->g.x0-ox)/TTDX; /* >>4; */

    temp=redrawstr->g.x1-ox;
    xhi=temp/TTDX; /* >>4; */
    if((xhi*TTDX)!=temp) xhi++;

    if(xhi>width) xhi=width;

    if(flags==RDATA)
    {
     if(xlo<oldrlo) xlo=oldrlo;
     if(xhi>oldrhi) xhi=oldrhi;
    }

    xhilo=xhi-xlo;

    if(usemode==15 || usemode==21) xhilo*=2;
    else
    if(usemode==MX169090 || usemode==MX169045) xhilo*=4;
    else
    if(usemode==MX329090 || usemode==MX329045) xhilo*=8;

    tspa->width=xhilo-1;
    spwidth=xhilo*4;

    xplot=ox+xlo*TTDX;
   }

   oldattr=(attr>0);

   if(xlo>=xhi) continue;

   if(ttyx>=xlo && ttyx<=xhi && y==yc) atrf=attr>0;

   if(cachedata!=(data+xlo) || cachexhilo!=xhilo || flags==RDATA)
   {
    cachedata=data+xlo;
    cachexhilo=xhilo;


   if(usemode>MXNEWMODE)
   {
    if(usemode==MX329090)
    {
     if(attr==VTASW)  line329090S(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADW)  line329090D(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHT) line329090DT(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHB) line329090DB(&data[xlo],image,xhilo,spwidth);
    }
    else
    if(usemode==MX329045)
    {
     if(attr==VTASW)  line329045S(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADW)  line329045D(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHT) line329045DT(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHB) line329045DB(&data[xlo],image,xhilo,spwidth);
    }
    else
    if(usemode==MX169090)
    {
     if(attr==VTASW)  line169090S(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADW)  line169090D(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHT) line169090DT(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHB) line169090DB(&data[xlo],image,xhilo,spwidth);
    }
    else
    if(usemode==MX169045)
    {
     if(attr==VTASW)  line169045S(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADW)  line169045D(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHT) line169045DT(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHB) line169045DB(&data[xlo],image,xhilo,spwidth);
    }
   }
   else
   if(usemode>15)
   {
    if(usemode==20)
    {
     if(attr==VTASW) line18S(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADW) line18D(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHT) line18DT(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHB) line18DB(&data[xlo],image,xhilo,spwidth);
    }
    else
    {
     if(attr==VTASW) line23S(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADW) line23D(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHT) line23DT(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHB) line23DB(&data[xlo],image,xhilo,spwidth);
    }
   }
   else
   {
    if(usemode==12)
    {
     if(attr==VTASW) line00S(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADW) line00D(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHT) line00DT(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHB) line00DB(&data[xlo],image,xhilo,spwidth);
    }
    else
    {
     if(attr==VTASW) line15S(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADW) line15D(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHT) line15DT(&data[xlo],image,xhilo,spwidth);
     else
     if(attr==VTADHB) line15DB(&data[xlo],image,xhilo,spwidth);
    }
   }
   }



/*   if(y==ystat)
   {
    int colour;

    yplot-=deltay;

    colour=physicalcolour(vtvhi?CERICE:WHITE,vtvhi?0:2);
    if(ln2bpp!=3) colour&=0xF;

    setgcolour(colour,0);

    bbc_move(xplot,yplot+TTDY);
    bbc_draw(xplot+xhilo*TTDX,yplot+TTDY);
   }
       */

   if(notrans)
               sprite_put_given((sprite_area *)tsprite,&spid,0,xplot,yplot);
   else
               sprite_put_scaled((sprite_area *)tsprite,&spid,0,xplot,yplot,
                                                   scalefactors,pixtrans);




   /* a continue comes here ... */
  } 
  

  if(y<yhi && flags!=RDRAW)
  {
   wimp_setcolour(7);
   bbc_rectanglefill(redrawstr->g.x0,oy-y*TTDY-deltay,
                            redrawstr->g.x1-redrawstr->g.x0,-(yhi-y)*TTDY);
  }

                                        
  if(atrf>=0 && !vtmovecurs)
  {
   if(vtcurs && vtcursphase)
   {
    /* draw cursor */
    seteorcol(0,7);
    if(vtblock)
    {
     bbc_rectanglefill(ox+(ttyx<<atrf)*TTDX,oy-(yc+1)*TTDY+deltay,
                                          (TTDX<<atrf)-deltax,TTDY-2*deltay);
    }
    else
    {
     bbc_move(ox+(ttyx<<atrf)*TTDX,oy-(yc+1)*TTDY+deltay);
     bbc_draw(ox+(ttyx<<atrf)*TTDX+(TTDX<<atrf)-deltax,oy-(yc+1)*TTDY+deltay);
    }
   }
  }

  wimp_get_rectangle(redrawstr,&more);
 }
}




void redrawvt(void)
{
 wimp_redrawstr redrawstr;
 int            more;
 redrawstr.w=ewindow;
 wimp_redraw_wind(&redrawstr,&more);
 redrawvtsub(&redrawstr,more,RDRAW,0);
}




/* called to redraw any areas of the screen that we have changed */
/* vtpendshift -ve implies screen contents are going downwards   */


void vtdoredraw(void)
{
 wimp_redrawstr redrawstr;
 int more;
 int xlo;
 int xhi;
 int ylo;
 int yhi;
 int y;
 tline * lp;
 int statusline=0;


 xlo=((vtx0-vtbx)/TTDX);
 xhi=((vtx1-vtbx)/TTDX)+1;

 if(vtvert)
 {
  ylo=((vtby-vty1-tscrolly+vtpendshift)/TTDY)-1;  /* -2*vtpend */
  yhi=((vtby-vty0-tscrolly+vtpendshift)/TTDY);
 }
 else
 {
  ylo=((vtby-vty1+vtpendshift)/TTDY)-1;       /* was -ve */
  yhi=((vtby-vty0+vtpendshift)/TTDY);
 }

 /* y's are absolute buffer address's can't be bigger than buffsize */

 if(yhi>buffsize) yhi=buffsize-1;
 if(ylo<0)        ylo=0;

 if(ylo>=yhi) return;


 /* scan this area to find area in need of redraw */

 while(1)
 {
  lp=vtindex(ylo);
  if(lp->rlo!=lp->rhi) break;
  ylo++;
  if(ylo>=yhi) break;
 }

 while(1)
 {
  lp=vtindex(yhi);
  if(lp->rlo!=lp->rhi) break;
  yhi--;
  if(yhi<=ylo) break;
 }


 if(ylo>yhi) return;

 redrawstr.w=whandle[VTERM];
 redrawstr.box.x0=xlo*TTDX;
 redrawstr.box.x1=xhi*TTDX;
 redrawstr.box.y0=-(yhi+1)*TTDY-tscrolly-vtpendshift;  /* - tscrolly */
 redrawstr.box.y1=-(ylo*TTDY)-tscrolly-vtpendshift;    /* - tscrolly */



 if(vtheight==25 && ((redrawstr.box.y0+tscrolly)<-TTDY*(tops+24)) &&
                                                              vtpendshift)
 {
  redrawstr.box.y0=-TTDY*(tops+24)-tscrolly;
  statusline=1;
 }
 else statusline=0;


 if(((redrawstr.box.y0+tscrolly)<-TTDY*(tops+24)) && vtpendshift)
                         redrawstr.box.y0=-TTDY*(tops+24)-tscrolly;


 if(!vtvert)
 {
  redrawstr.box.y0+=tscrolly;
  redrawstr.box.y1+=tscrolly;
 }

 wimp_update_wind(&redrawstr,&more);
 redrawvtsub(&redrawstr,more,RDATA,vtpendshift);


 for(y=ylo;y<=(yhi-statusline);y++)
 {
  lp=vtindex(y);
  lp->rlo=lp->rhi=0;
 }
}



/* called to redraw any areas of the screen that are flashing */

void vtgenflashupdate(void)
{
 int xlo;
 int xhi;
 int cxlo;
 int cxhi;
 int xxhi;
 int ylo;
 int yhi;
 int flo;
 int fhi;
 int atrf;
 tline * lp;


 xlo=((vtx0-vtbx)/TTDX); /* >>4); */
 xhi=(vtx1-vtbx);
 xxhi=xhi;
 xhi=xhi/TTDX; /* >>4; */

 ylo=((vtby-vty1-tscrolly)/TTDY);
 yhi=((vtby-vty0-tscrolly)/TTDY)+1;

 if(yhi>buffsize) yhi=buffsize;

 /* scan this area to find area in need of redraw */

 while(ylo<=yhi)
 {
  lp=vtindex(ylo);
  if(lp->flo!=lp->fhi)
  {
   atrf=lp->attr>0;

   if(atrf)
   {
    cxlo=xlo>>1;
    cxhi=(xhi>>1);
    if((cxhi*2*TTDX)!=xxhi) cxhi++;
   }
   else
   {
    cxlo=xlo;
    cxhi=xhi;
    if((cxhi*TTDX)!=xxhi) cxhi++;
   }

   if(cxhi>width) cxhi=width;

   flo=lp->flo;
   fhi=lp->fhi;
   if(flo<cxlo) flo=cxlo;
   if(fhi>cxhi) fhi=cxhi;
      
   if(flo<fhi)
   {
    lp->rlo=flo;
    lp->rhi=fhi;
    vtpendredraw=1;
   }
  }
  ylo++;
 }
}



/*****************************************************************************/

void ledsoff(void)
{
 int i;
 
 for(i=0;i<4;i++)
 {
  vtleds[i]=0;
 }
 vtwriteleds();
}

void ledon(int i)  /* i in range 1 to 4 */
{
 if(i>4) return;
 i--;              /* range 0 to 3 */
 vtleds[i]=1;
 vtwriteleds();
}



/*****************************************************************************/




void vtnewzoom(int mul,int div)
{
 int oldttdy;

 if(mul==vtzoom.mul && div==vtzoom.div) return;
 if(mul*vtzoom.div==div*vtzoom.mul) return;
 vtzoom.mul=mul;
 vtzoom.div=div;

 oldttdy=TTDY;

 createtermsprite();

 tscrolly=(tscrolly*TTDY)/oldttdy;
 reopenvertical();

 refreshwindow(whandle[VTERM]);
}





void vtsetvarzoom(void)
{
 int h;
 int w;
 int xmul;
 int xdiv;
 int ymul;
 int ydiv;


 w=(vtx1-vtx0)/width;     /* os units per char */
 h=(vty1-vty0)/vtheight;  /* os units per char */

 xmul=w/deltax;
 if(w % deltax) xmul++;               /* pixels per char        */
 xdiv=(TTBDX/deltax);                 /* pixels per normal char */
                                   
 ymul=h/deltay;
 if(h % deltay) ymul++;               /* pixels per char        */
 ydiv=(TTBDY/deltay);                 /* pixels per normal char */

 if(xmul*ydiv>ymul*xdiv) vtnewzoom(xmul,xdiv);
 else                    vtnewzoom(ymul,ydiv);
}






void vtwimpopenwindows(wimp_openstr * wopen)
{
 int oldtscrolly;

 clipwindow(wopen,0);

 wimp_open_wind(wopen);
 getw(whandle[VTERM]);
 geto(whandle[VTERM]);

 vtx0=x0;
 vtx1=x1;
 vty0=y0;
 vty1=y1;
 vtscx=scx;
 vtscy=scy;
 vtbx=bx;
 vtby=by;

 if(vtvert)
 {
  oldtscrolly=tscrolly;
/*  open(whandle[VTVERT],x1,y0-40,x1,y1+40,0,tscrolly,whandle[VTERM]); */
  open(whandle[VTVERT],x1,oy0+deltay,x1,oy1-deltay,0,tscrolly,whandle[VTERM]);
  getw(whandle[VTVERT]);
  tscrolly=scy;

  if(tscrolly!=oldtscrolly) vtscroll(oldtscrolly-tscrolly,1);
 }
 else
 {
  tscrolly=scy;
 }

 if(vtzoom.var) vtsetvarzoom();
}





void reopenvertical(void)
{
 wimp_wstate winds;
 wimp_get_wind_state(whandle[VTVERT],&winds);
 winds.o.y=tscrolly;
 wimp_open_wind(&winds.o);
}




/* called when a new zoom is set */

void vtdozoom(void)
{
 wimp_wstate winds;
 int handle=whandle[VTERM];
 int vertical=whandle[VTVERT];

 createtermsprite();

 if(vtvert)
 {
  extent(handle,0,-vtheight*TTEDY,width*TTEDX,0);
  extent(vertical,0,-buffsize*TTEDY-80,0,0);
 }
 else
 {
  extent(handle,0,-buffsize*TTEDY,width*TTEDX,0);
 }

 wimp_get_wind_state(handle,&winds);
 vtwimpopenwindows(&winds.o);

 refreshwindow(handle);
}





/* called when we go var zoom */

void vtvarzoom(void)
{
 wimp_wstate winds;
 int handle=whandle[VTERM];
 int vertical=whandle[VTVERT];

 if(vtvert)
 {
  extent(handle,0,-vtheight*TTEDY,width*TTEDX,0);
  extent(vertical,0,-buffsize*TTEDY-80,0,0);
 }
 else
 {
  extent(handle,0,-buffsize*TTEDY,width*TTEDX,0);
 }

 wimp_get_wind_state(handle,&winds);
 vtwimpopenwindows(&winds.o);

 vtsetvarzoom();
}




/***************************************************************************/


/* shifts the contents of the VT scroll zone */
/* uses vtsuby , vtsubn and vtsubdelta       */

void vtclearsub(void)
{
 int ox0;
 int ox1;
 int oy0;
 int oy1;

 int ny0;

 int sy0;
 int sy1;

 wimp_box box;
 wimp_redrawstr redrawstr;
 int  more;

 int  dshift;
 int  shift;

 if(!vtpendsubs) return;

 shift=vtsubdelta*TTDY;

 if(abs(shift)>2*TTDY || !smooth) dshift=-shift;
 else
 {
  dshift=-(shift/4);
  dshift&=masky;
 }

 if(vtvert)
 {
  sy0=-(tops+vtsuby+vtsubn+1)*TTDY-tscrolly;
  sy1=-(tops+vtsuby)*TTDY-tscrolly;
 }
 else
 {
  sy0=-(tops+vtsuby+vtsubn+1)*TTDY;
  sy1=-(tops+vtsuby)*TTDY;
 }


 ox0=vtx0-vtbx;
 ox1=vtx1-vtbx;
 oy0=vty0-vtby;  /* + tscrolly */
 oy1=vty1-vtby;

 if(sy1<oy0 || sy0>oy1) shift=0;  /* scroll zone is out of window */

 while(shift)
 {
  if(shift>(-dshift) && (shift+2*dshift)<0) dshift=-shift;
  else
  if(shift<(-dshift) && (shift+2*dshift)>0) dshift=-shift;

  if(dshift>0)     /* scroll down */
  {
   box.x0=ox0;
   box.x1=ox1;

   if(dshift<(sy1-sy0))
   {
    ny0=sy0;
    box.y0=sy0+dshift;
    box.y1=sy1;
    wimp_blockcopy(whandle[VTERM],&box,ox0,ny0);
    redrawstr.box.y0=sy1-dshift;
    redrawstr.box.y1=sy1;
   }
   else
   {
    redrawstr.box.y0=sy0;
    redrawstr.box.y1=sy1;
   }

   redrawstr.w=whandle[VTERM];
   redrawstr.box.x0=ox0;
   redrawstr.box.x1=ox1;
  }
  else             /* scroll up */
  {
   box.x0=ox0;
   box.x1=ox1;

   if(dshift>(sy0-sy1))
   {
    ny0=sy0-dshift;
    box.y0=sy0;
    box.y1=sy1+dshift;
    wimp_blockcopy(whandle[VTERM],&box,ox0,ny0);
    redrawstr.box.y0=sy0;
    redrawstr.box.y1=sy0-dshift;
   }
   else
   {
    redrawstr.box.y0=sy0;
    redrawstr.box.y1=sy1;
   }

   redrawstr.w=whandle[VTERM];
   redrawstr.box.x0=ox0;
   redrawstr.box.x1=ox1;
  }

  wimp_update_wind(&redrawstr,&more);
  redrawvtsub(&redrawstr,more,NLINE,0 /* shift+dshift */);

  shift+=dshift;
 }

 vtpendsubs=0;
}





/* shifts the contents of the VT window by given amount */

void vtscroll(int shift,int scrollbar)
{
 int ox0;
 int ox1;
 int oy0;
 int oy1;

 int ny0;
 int ny1;

 wimp_box box;
 wimp_redrawstr redrawstr;
 int  more;

 int  dshift;


 if(scrollbar || abs(shift)>2*TTDY || !smooth) dshift=-shift;
 else
 {
/*  dshift=-(shift/4); */
  dshift=-(shift/9);
  dshift&=masky;
 }

 while(shift)
 {
  if(shift>(-dshift) && (shift+2*dshift)<0) dshift=-shift;
  else
  if(shift<(-dshift) && (shift+2*dshift)>0) dshift=-shift;


  ox0=vtx0-vtbx;
  ox1=vtx1-vtbx;
  oy0=vty0-vtby;
  oy1=vty1-vtby;

  if(!scrollbar)
  {
   if(vtheight==25)
   {
    if((oy0+tscrolly)<-TTDY*(tops+24))      oy0=-TTDY*(tops+24)-tscrolly;
    if((oy0+tscrolly-dshift)<-TTDY*(tops+24)) 
                                           oy0=-TTDY*(tops+24)-tscrolly+dshift;
   }
   else
   {
    if((oy0+tscrolly)<-TTDY*(tops+24)) oy0=-TTDY*(tops+24)-tscrolly;
    if((oy0+tscrolly-dshift)<-TTDY*(tops+24))
                                         oy0=-TTDY*(tops+24)-tscrolly+dshift;
   }
  }

  ny0=oy0-dshift;
  ny1=oy1-dshift;

  if(ny0<oy1 && ny1>oy0)
  {
   box.x0=ox0;
   box.x1=ox1;
   box.y0=oy0;
   box.y1=oy1;


   wimp_blockcopy(whandle[VTERM],&box,ox0,ny0);
  }
  else
  {
   if(ny0>oy1) ny0=oy1;
   if(ny1<oy0) ny1=oy0;
  }

  if(!scrollbar) vtpendshift+=dshift;

  redrawstr.w=whandle[VTERM];
  redrawstr.box.x0=ox0;
  redrawstr.box.x1=ox1;

  if(dshift<0)                /* ((-dshift)>0) */
  {
   redrawstr.box.y0=oy0;
   redrawstr.box.y1=ny0;
  }
  else
  {
   redrawstr.box.y0=ny1;
   redrawstr.box.y1=oy1;
  }

  wimp_update_wind(&redrawstr,&more);
  redrawvtsub(&redrawstr,more,NLINE,vtpendshift);

  shift+=dshift;
 }
}




/* the vertical scroll bar has been tweeked */

void openvtvert(void)
{
 int shift;

 if(vtopen)
 {
  wimp_open_wind(&(wimpevent.data.o));
  getw(whandle[VTVERT]);
  shift=tscrolly-scy;
  tscrolly=scy;
  vtscroll(shift,1);
 }
}


void openvt(void)
{
 if(vtopen) vtwimpopenwindows(&(wimpevent.data.o));
}




void vtgoffset(int sscx,int sscy)
{
 int         shift;
 wimp_wstate winds;
 int         oldtscroll;


 shift=tscrolly-sscy;
 if(shift && vtvert)
 {
  wimp_get_wind_state(whandle[VTVERT],&winds);
  oldtscroll=tscrolly;
  tscrolly=sscy;
  winds.o.y=tscrolly;

  wimp_open_wind(&winds.o);

  wimp_get_wind_state(whandle[VTVERT],&winds);
  tscrolly=winds.o.y;
  shift=oldtscroll-tscrolly;

  vtscroll(shift,1);
 }

 wimp_get_wind_state(whandle[VTERM],&winds);

 if(sscx!=winds.o.x || (!vtvert && sscy!=winds.o.y))
 {
  winds.o.x=sscx;
  if(!vtvert) winds.o.y=sscy;
  wimp_open_wind(&winds.o);
  getw(whandle[VTERM]);
  vtscx=scx;
  vtscy=scy;
  if(!vtvert) tscrolly=scy;
  vtbx=bx;
 }
}





void vtsetfocus(void)
{
 setfocus(whandle[VTERM]);
 if(terminalmodeset) terminalmode=TMODEVT;
}



void vtsetfocusfront(void)
{
 wimp_wstate wblock;
 wimp_get_wind_state(whandle[VTERM],&wblock);
 wblock.o.behind=-1;
 vtwimpopenwindows(&wblock.o);
 clearzone();
 vtsetfocus();
}


void vtclick(void)
{
 if(buttons & 0x2) popmain();
 else
 {
  findcaret();
  if(chandle!=whandle[VTERM])
  {
   clearzone();
   vtsetfocus();
  }
  else
  {
   switch(buttons)
   {
     case   0x1:             /* double click with adjust */
                vtmarkcursortomouse();
                break;

     case   0x4:             /* double click with select */
                vthomecursortomouse();
                break;

     case 0x100:             /* single click with adjust */
                vtsendreturn();
                break;

     case 0x400:             /* single click with select */
                vtsendcursorcode();
                break;

     case  0x40:             /* drag with select */
                vtstartdrag();
                break;
   }
  }
 }
}



void vtzero(void)
{

 if(!vtpendredraw && !vtpendscrolly && !vtpendshift)
 {
  if(vtflashtime<zerotime)
  {
   vtflashtime=zerotime+50;
   vtflashphase^=VTFLASH;
   tflashflash(vtflashphase);
   vtgenflashupdate();
  }
 }

 if(vtcurs)
 {
  if(vtcurstime<zerotime || vtmovecurs)
  {
   if(vtmovecurs) vtcursphase=1;
   else           vtcursphase^=1;
   vtcurstime=zerotime+50;
   if(vtcursphase || !vtmovecurs) vtredraw(ttyy,ttyx,ttyx);
   if(vtmovecurs)                 vtwritecursorposn();
   vtmovecurs=0;
  }
 }

 if(vtpendsubs) vtclearsub();

 if(vtpendredraw)
 {
  vtdoredraw();
  vtpendredraw=0;
 }
  

 if(vtpendscrolly)
 {
  reopenvertical();
  vtpendscrolly=0;
 }


 if(vtpendshift)
 {
  vtscroll(vtpendshift,0);
  vtpendshift=0;
 }
}


void vtmodechange(void)
{

 createtermsprite();

/*dprintf(0,"vtmode change 1"); */

 if(newcolourmap()) docolourmap();

/* dprintf(0,"vtmode change 2"); */

 setstylec();
 setsys();
}


void vtpalchange(void)
{

/* dprintf(0,"vtpal change 0"); */

 createtermsprite();

/* dprintf(0,"vtpal change 1"); */

 if(newcolourmap()) docolourmap();

/* dprintf(0,"vtpal change 2"); */

 setstylec();
 setsys();
}





/****************************************************************************/


void gaincsub(int gain,int bh)
{
 int wh;
 char stuff[1024];
 wimp_winfo * ww=(wimp_winfo*)stuff;
 wimp_wstate wst;

 ww->w=whandle[VTVERT];

 wimp_get_wind_info(ww);


 if(gain) ww->info.colours[wimp_WCTITLEBACK]=12;
 else     ww->info.colours[wimp_WCTITLEBACK]=2;

 wimp_delete_wind(whandle[VTVERT]);

 wimp_create_wind(&ww->info,&wh);

 wimp_get_wind_state(wh,&wst);
 wst.o.behind=bh;

 wimp_open_wind(&(wst.o));

 whandle[VTVERT]=wh;
}


int gainedc=0;

void gaincsz(void)
{

 if(vtopen) 
 {
  if(vtvhi!=gainedc)
  {
   if(vtvert) gaincsub(gainedc,whandle[VTERM]);
   vtvhi=gainedc;
   vtrefreshstatus();
  }
 }

 remzeroevent(VTGAINC);
}


void gaincs(int gain)
{
 getpointer();

/* if(mhandle==whandle[VTERM] && micon<-3) 
 { */
  addzeroevent(VTGAINC);
/* }
 else
 if(vtvhi!=gain)
 {
  gaincsub(gain,whandle[VTERM]);
  vtvhi=gain;
  vtrefreshstatus();
 } */

 gainedc=gain; 
}







