/*      VERSION 0016
  paint.c (144) (42)
  painting functions

  new for DC intelligent repaint                                      0001
  manage screen line queue                                            0005
*/

#include  <stdio.h>
#include  <math.h>
#include  <windows.h>

#define maxCOLORS 8
#define maxLINES  30
#define nostic    fprintf(stdprn,
#define curse(a)  SetCursor(LoadCursor(NULL,a))
#define mad(i,j)  (i+j)%maxLINES
#define   TXx     CharWid*(curpos%ScrWid)
#define   TXy     CharHgt*curlin


typedef struct{
  HANDLE  h;
  short   color;
  } LINETAB;

static
LINETAB lines[maxLINES];    /* line queue */
static
short   lc=0,   /* insert pt--tail */
        top=0;  /* top line on screen--head */

/* std IBM color map 8 */
static
DWORD colors[maxCOLORS]={
  RGB(0,0,0),    RGB(0,0,255),  RGB(0,128,0),  RGB(0,255,255),
  RGB(255,0,0),  RGB(255,255,0),RGB(255,0,255),RGB(255,255,255)
  };

extern
int     curpos,   /* current col and bufpos */
        curlin,   /* current line */
        ScrWid,   /* screen bounds */
        ScrHgt,   /*   in chars    */
        CharWid,  /* character width */
        CharHgt;  /*   and height    */
extern
BOOL    initted;  /* data initialized flag */

/* lGetBuf
    allocate local buffer for data and copy to it
*/
static
HANDLE  lGetBuf(s,siz)
  char      *s;
  unsigned  siz;
{
  HANDLE    g;
  char      *ch;
  unsigned  i;

  LockData(0);
  g=LocalAlloc(LMEM_MOVEABLE,(DWORD)siz);
  if(g!=NULL &&
     (ch=(char *)LocalLock(g))!=NULL){
    memcpy(ch,s,siz);
    LocalUnlock(g);
  }
  UnlockData(0);
  return g;
} /* lGetBuf */

/* KillTop
    frees item at TOP and advances TOP if possible
*/
KillTop()
{
  if(top!=lc){
    LocalFree(lines[top].h);
    top=mad(top,1);
  }
} /* KillTop */

/* addline
    adds a new line to the line database of color C
    also draws the new line and scrolls if needed.
    prevent caret interference.
*/
addline(hWnd,line,c)
  HWND  hWnd;
  char  *line;
  int   c;
{
  HANDLE  h;
  char    *p;
  HDC     dc;
  int     l;

  l=strlen(line);
  if(line[l-1]=='\n') line[--l]='\0';
  h=lGetBuf(line,l+1);
  if(h!=(HANDLE)NULL){
    lines[lc].h=h,lines[lc].color=(short)c;
    lc=mad(lc,1);
    p=(char *)LocalLock(h);
    HideCaret(hWnd);
    dc=GetDC(hWnd);
    SetTextColor(dc,colors[c]);
    TextOut(dc,TXx,TXy,(LPSTR)p,strlen(p));
    ReleaseDC(hWnd,dc);
    LocalUnlock(h);
    if(curlin>=ScrHgt){
      ScrollWindow(hWnd,0,-CharHgt,(LPRECT)NULL,(LPRECT)NULL);
      KillTop();
    }
    curlin=(curlin<ScrHgt)?curlin+1:curlin;
    SetCaretPos(0,TXy);
    ShowCaret(hWnd);
  }
} /* addline */

/* paint
    update the DC display, only parts which need to be redrawn.
    updates lines which fall in the update rectangle.
    this is nearly the best we can do for text.
*/
paint(hWnd,ps,dc)
  HWND          hWnd;
  PPAINTSTRUCT  ps;
  HDC           dc;
{
  int   i,j,start=0,stop=0;
  char  *p;

  LockData(0);
  if(ps->fErase)
    FillRect(dc,(LPRECT)&(ps->rcPaint),GetStockObject(WHITE_BRUSH));
  if(initted){
    start=ps->rcPaint.top/CharHgt; stop=ps->rcPaint.bottom/CharHgt;
  }
  UnlockData(0);
  for(i=mad(top,start),j=start;i!=lc && j<=stop;i=mad(i,1),j++){
    p=(char *)LocalLock(lines[i].h);
    if(p!=NULL){
      SetTextColor(dc,colors[lines[i].color]);
      TextOut(dc,0,CharHgt*j,(LPSTR)p,strlen(p));
      LocalUnlock(lines[i].h);
    }
  }
} /* paint */

