dword hout;
dword hin;

int verthoriz=0;
int shownums=1;

char str[MAX_PATH];
word attr[MAX_PATH];

printstrat(int x,y,size,ch,at)
{
  WriteConsoleOutputAttribute(hout,at,size,y<<16+x,#at);
  WriteConsoleOutputCharacter(hout,ch,size,y<<16+x,#at);
}

drawborder(dword x1,y1,xs1,ys1,fname,line)
char temp[MAX_PATH];
int  titlelen;
{
  int i,j;

  FillMemory(#str,xs1,'═');
  FillMemory(#attr,xs1*2,0x1F);

  str[0]='╚'; str[xs1-1]='╝';
  printstrat(x1,y1+ys1-1,xs1,#str,#attr); //нижняя строчка

  str[0]='╔'; str[xs1-1]='╗';
  titlelen=xs1-4;
  IF(!shownums)titlelen-=8;
  IF(lstrlen(fname)>titlelen)wsprintf(#temp," ...%s ",lstrlen(fname)+fname-titlelen+3);
                        ELSE wsprintf(#temp," %s ",fname);
  FOR(i=0;temp[i];i++){ str[i+1]=temp[i]; attr[i+1]=0x1E; }
  IF(!shownums)
  {
    wsprintf(#temp,"[%6d]",line);
    CopyMemory(xs1-9+#str,#temp,8);
    FillMemory(xs1-8*2+#attr,12,0x19);
  }
  printstrat(x1,y1,xs1,#str,#attr);
}

drawline(int x,y,xs,linex,s1,s2,ln)
{
  int i;
  int s1l;
  int s2l;
  int c1,c2;
  char temp[10];
  int x2,xs2;


  s1l=-1;
  s2l=-1;
  IF(s1!=-1)s1l=lstrlen(s1);
  IF(s2!=-1)s2l=lstrlen(s2);

  FillMemory(#attr,xs*2,0x1F);
  str[0]='║'; str[x+xs-1]='║';

  IF(s1==-1)
  {
    FillMemory(#str[1],xs-2,'·');
    FillMemory(#attr[2],xs-2*2,7);
  }else{//строка присутствует
    x2=1;
    xs2=xs;
    IF(shownums)
    {
      wsprintf(#temp,"%6d",ln+1);
      FOR(i=0;i<6;i++)
      {
        str[i+1]=temp[i];
        attr[i+1]=0x19;
      }
      str[7]='│';
      x2+=7;
      xs2-=7;
    }
    IF(s1>0)&&(s2>0)&&(!_lstrcmp(s1,s2))
    {//строки совпадают
      FOR(i=0;i<xs2-2;i++)
        IF(i+linex<s1l)str[x2+i]=DSBYTE[s1+i+linex];ELSE str[x2+i]=' ';
    }else
    {
      FOR(i=0;i<xs2-2;i++)
      {
        IF(i+linex<s1l)c1=DSBYTE[s1+i+linex]; ELSE c1=' ';
        IF(i+linex<s2l)c2=DSBYTE[s2+i+linex]; ELSE c2=' ';
        str[x2+i]=c1;
        IF(c1==c2)attr[x2+i]=0x4F;ELSE attr[x2+i]=0x4E;
      }
    }
  }
  printstrat(x,y,xs,#str,#attr);
}

printpanel(dword line,linex ,x1,y1,xs1,ys1 ,x2,y2,xs2,ys2)
{
  int i,j;
  int s,d,sl,dl;
  int line1,line2;

  FOR(j=line;j<srcfilenums.Count;j++){ s=srcfilenums.At(j); IF(s!=-1)BREAK; }
  IF(s==-1)s=srcfilelines.Count-1;
  drawborder(x1,y1,xs1,ys1,srcfilename,s+1);

  FOR(j=line;j<dstfilenums.Count;j++){ d=dstfilenums.At(j); IF(d!=-1)BREAK; }
  IF(d==-1)d=dstfilelines.Count-1;
  drawborder(x2,y2,xs2,ys2,dstfilename,d+1);
  for(j=0;j<ys1-2;j++)
  {
    IF(j+line<srcfilenums.Count)s=srcfilenums.At(j+line); ELSE s=-1;
    line1=s;
    IF(s!=-1)s=srcfilelines.At(s);
    IF(j+line<dstfilenums.Count)d=dstfilenums.At(j+line); ELSE d=-1;
    line2=d;
    IF(d!=-1)d=dstfilelines.At(d);
    drawline(x1,y1+j+1,xs1,linex,s,d,line1);
    drawline(x2,y2+j+1,xs2,linex,d,s,line2);
  }
}

printkeybar(dword xs,y)
{
  int i,j;
  int c=0x70;

  FillMemory(#str,sizeof(str),' ');
  FillMemory(#attr,sizeof(attr),c);
  i=0;
  FOR(j=0;strbar[j];j++)
  {
    IF(strbar[j]=='~')
    {
      IF(strbar[j+1]=='~')j++;
      ELSE
      {
        c^=4; CONTINUE;
      }
    }
    str[i]=strbar[j];
    attr[i]=c;
    i++;
  }
  printstrat(0,y,xs,#str,#attr);
}


h(dword type)
{
  IF(type==0/*CTRL_C_EVENT*/)
  ||(type==1/*CTRL_BREAK_EVENT*/)
  {
    RETURN 1;
  }
  IF(type==2/*CTRL_CLOSE_EVENT*/)
  {
  }
  return 0;
}

ifinit()
int linenum=0;
int linex=0;
int ys;
INPUT_RECORD ir;
CONSOLE_SCREEN_BUFFER_INFO sbi;
CONSOLE_CURSOR_INFO curinfo,newcurinfo;
{
  int i;

  hout=GetStdHandle(STD_OUTPUT_HANDLE);
  hin=GetStdHandle(STD_INPUT_HANDLE);
  GetConsoleScreenBufferInfo(hout,#sbi);

  SetConsoleCtrlHandler(#h,1);

  GetConsoleCursorInfo(hout,#curinfo);
  GetConsoleCursorInfo(hout,#newcurinfo);
  newcurinfo.bVisible=0;
  SetConsoleCursorInfo(hout,#newcurinfo);

  linenum=diffs.At(0);

  printkeybar(sbi.dwSize.x,sbi.dwSize.y-1);
  sbi.dwSize.y--;
  ys=sbi.dwSize.y-2;goto checkupper;//!!!

@redraw:
  IF(!verthoriz)
  {
    printpanel(linenum,linex
              ,0,0
              ,sbi.dwSize.x/2 ,sbi.dwSize.y
              ,sbi.dwSize.x/2 ,0
              ,sbi.dwSize.x/2 ,sbi.dwSize.y
    );
    ys=sbi.dwSize.y-2;
  }
  else
  {
    printpanel(linenum,linex
              ,0,0
              ,sbi.dwSize.x ,sbi.dwSize.y/2
              ,0            ,sbi.dwSize.y/2
              ,sbi.dwSize.x ,sbi.dwSize.y/2
    );
    IF(sbi.dwSize.y&1)
    {
      FillMemory(#str,sbi.dwSize.x,'░');
      FillMemory(#attr,sbi.dwSize.x*2,0x71);
      printstrat(0,sbi.dwSize.y-1,sbi.dwSize.x,#str,#attr);
    }
    ys=sbi.dwSize.y/2-2;
  }
  while(ReadConsoleInput(hin,#ir,1,#i))
  {
    if(ir.EventType==1/*KEY_EVENT*/)
    {
      if(ir.KeyEvent.bKeyDown)
      {
        IF(ir.KeyEvent.dwControlKeyState&0x0C00)ir.KeyEvent.wVirtualKeyCode|=0x8000;//ctrl
        IF(ir.KeyEvent.dwControlKeyState&0x1000)ir.KeyEvent.wVirtualKeyCode|=0x4000;//shift
        IF(ir.KeyEvent.dwControlKeyState&0x0300)ir.KeyEvent.wVirtualKeyCode|=0x2000;//alt
        switch(ir.KeyEvent.wVirtualKeyCode)
        {
          case 0x1B/*VK_ESCAPE*/: goto end;
          case 0x74/*VK_F5*/: verthoriz^=1; goto redraw;

          case 0x26/*VK_UP*/: linenum--;
                              @checkupper:
                              IF(linenum+ys>srcfilenums.Count)linenum=srcfilenums.Count-ys;
                              IF(linenum<0)linenum=0;
                              goto redraw;

          case 0x28/*VK_DOWN*/: linenum++; goto checkupper;

          case 0x21/*pgup*/: linenum-=ys; goto checkupper;
          case 0x22/*pgdn*/: linenum+=ys; goto checkupper;

          case 0x8021: linenum=0; goto checkupper;
          case 0x8022: linenum=srcfilenums.Count; goto checkupper;

          case 0x24/*home*/: linex=0; goto redraw;
          case 0x25/*VK_LEFT*/: IF(linex>0)linex--; goto redraw;
          case 0x27/*VK_RIGHT*/: IF(linex<0xFF)linex++; goto redraw;

          case 'N': shownums^=1; goto redraw;

          case 0x6B/*+*/: diffs.Search(linenum+1,#linenum);
                          @pluspressed:
                          IF(linenum>=diffs.Count)IF(diffs.Count)linenum=diffs.Count-1;
                          linenum=diffs.At(linenum);
                          goto checkupper;

          case 0x6D/*-*/: diffs.Search(linenum,#linenum);
                          IF(linenum>0)linenum--;
                          linenum=diffs.At(linenum);
                          goto checkupper;
/*
          case 0x8011:
          case 0x4010:
          case 0x2012:
          case 0x10: goto redraw;
          default: wsprintf(#str,"[%04x=%04x=%04x]"
,ir.KeyEvent.wVirtualKeyCode
,ir.KeyEvent.wVirtualScanCode
,ir.KeyEvent.dwControlKeyState
          );
FillMemory(#attr,16*2,7);
printstrat(i+62,sbi.dwSize.y,16,#str,#attr);
*/
        }
      }
    }
  }
  @end:
  FillConsoleOutputAttribute(hout,7,sbi.dwSize.y+1*sbi.dwSize.x,0,#ys);
  FillConsoleOutputCharacter(hout,' ',sbi.dwSize.y+1*sbi.dwSize.x,0,#ys);
  SetConsoleCursorInfo(hout,#curinfo);
}
