/* Warning! This C source contains extended characters! */

#include <dos.h>
#include <bios.h>
#include <string.h>
#include <stdlib.h>
#include <musique.h>
#include <window.e>

int coloroutline;
int colortitle;
/* colors of unpicked/picked menu items */
int coloritem;
int colorpicked;

/* background color of keyboard cursor */
int colorcurrent;
/* border color and background color of screen */
int colorborder;

void mycputs(PARAMETERTYPE *parameter, int x, int y, char text[], int color)
/* Turbo-C doesn't like extended or non-text modes */
/* Turbo-C scrolls the screen too much (lower-right corner) */
/* prints a string on the screen in the desired color */
/* no wrap around ever performed */
{
  union REGS regs;
  int position;
  char c;

  position=0;
  x--; y--;
  if (parameter->rawvideo) {
    x<<=1;
    x+=(y*parameter->maxcolumn)<<1;
    while ((c=text[position++])!='\0') {
      pokeb((unsigned)parameter->videosegment,(unsigned)x++,(int)c);
      pokeb((unsigned)parameter->videosegment,(unsigned)x++,color);
    }
  }
  else 
    while ((c=text[position++])!='\0') {
      regs.h.ah=(unsigned)'\x2'; /* set cursor position */
      regs.h.bh=(unsigned)'\x0';
      regs.h.dl=(unsigned char)x++;
      regs.h.dh=(unsigned char)y;
      int86(0x10,&regs,&regs);
      regs.h.ah=(unsigned)'\x9'; /* print one character */
      regs.h.bh=(unsigned)'\x0';
      regs.x.cx=(unsigned)0x1;
      regs.h.bl=(unsigned char)color;
      regs.h.al=(unsigned)c;
      int86(0x10,&regs,&regs);
    }
}

void myscrollup(PARAMETERTYPE *parameter)
/* scrolls up one line */
{
  union REGS regs;
  int x,y,source,target,RAM;

  if (parameter->rawvideo) {
    target=(parameter->maxcolumn<<2)+4;
    source=target+(parameter->maxcolumn<<1);
    for (y=2 ; y<=parameter->maxline-4 ; y++) {
      for (x=2 ; x<=parameter->maxcolumn-3 ; x++) {
        RAM=peek((unsigned)parameter->videosegment,(unsigned)source);
        poke((unsigned)parameter->videosegment,(unsigned)target,RAM);
        source+=2; target+=2;
      }  
      source+=8; target+=8;
    }
    for (x=2 ; x<=parameter->maxcolumn-3 ; x++) {
      pokeb((unsigned)parameter->videosegment,(unsigned)target,' ');
      target+=2;
    }
  }
  else {
    regs.x.ax=(unsigned)0x601;
    regs.h.bh=(unsigned char)colorborder;
    regs.x.cx=(unsigned)0x202;
    regs.h.dl=(unsigned char)(parameter->maxcolumn-3);
    regs.h.dh=(unsigned char)(parameter->maxline-3);
    int86(0x10,&regs,&regs);
    /* enables high intensity background */
    highbackground();
  }
}

void myscrolldown(PARAMETERTYPE *parameter)
/* scrolls down one line */
{
  union REGS regs;
  int x,y,source,target,RAM;

  if (parameter->rawvideo) {
    target=(((parameter->maxline-2)*parameter->maxcolumn)<<1)-6;
    source=target-(parameter->maxcolumn<<1);
    for (y=parameter->maxline-3 ; y>=3 ; y--) {
      for (x=2 ; x<=parameter->maxcolumn-3 ; x++) {
        RAM=peek((unsigned)parameter->videosegment,(unsigned)source);
        poke((unsigned)parameter->videosegment,(unsigned)target,RAM);
        source-=2; target-=2;
      }  
      source-=8; target-=8;
    }
    for (x=2 ; x<=parameter->maxcolumn-3 ; x++) {
      pokeb((unsigned)parameter->videosegment,(unsigned)target,' ');
      target-=2;
    }  
  }
  else {
    regs.x.ax=(unsigned)0x701;
    regs.h.bh=(unsigned char)colorborder;
    regs.x.cx=(unsigned)0x202;
    regs.h.dl=(unsigned char)(parameter->maxcolumn-3);
    regs.h.dh=(unsigned char)(parameter->maxline-3);
    int86(0x10,&regs,&regs);
    /* enables high intensity background */
    highbackground();
  }
}

void movecursor(PARAMETERTYPE *parameter)
/* moves the cursor out of the way one line too low */
{
  union REGS regs;

  regs.h.ah=(unsigned)'\x2';
  regs.h.bh=(unsigned)'\x0';
  regs.h.dl=(unsigned)'\x0';
  regs.h.dh=(unsigned char)parameter->maxline;
  int86(0x10,&regs,&regs);
}

void printoutline(PARAMETERTYPE *parameter)
/* prints a frame around the screen and the title */
/* leaves cursor around */
{
  int column,line;

  mycputs(parameter,1,1,"Ú",coloroutline|colorborder);
  for (column=2 ; column<parameter->maxcolumn ; column++)
    mycputs(parameter,column,1,"Ä",coloroutline|colorborder);
  mycputs(parameter,parameter->maxcolumn,1,"¿",coloroutline|colorborder);
  for (line=2 ; line<parameter->maxline ; line++) {
    mycputs(parameter,1,line,"³",coloroutline|colorborder);
    mycputs(parameter,parameter->maxcolumn,line,"³",coloroutline|colorborder);
  }
  mycputs(parameter,1,parameter->maxline,"À",coloroutline|colorborder);
  for (column=2 ; column<parameter->maxcolumn ; column++)
    mycputs(parameter,column,parameter->maxline,"Ä",coloroutline|colorborder);
  mycputs(parameter,parameter->maxcolumn,parameter->maxline,"Ù",
          coloroutline|colorborder);
  switch (language) {
    case FRENCH:column=(parameter->maxcolumn-strlen(FTITLE)+3)/2;
                mycputs(parameter,column,1,FTITLE,colortitle|colorborder);
                break;
    case ENGLISH:column=(parameter->maxcolumn-strlen(ETITLE)+3)/2;
                 mycputs(parameter,column,1,ETITLE,colortitle|colorborder);
                 break;
    case GERMAN:column=(parameter->maxcolumn-strlen(GTITLE)+3)/2;
                mycputs(parameter,column,1,GTITLE,colortitle|colorborder);
                break;
  }
}

void cleverwrapper(PARAMETERTYPE *parameter, int *wrapper, int *column)
/* evens out menu item columns nicely */
/* uses the modulo algorithm taken from the usual line drawing algorithm */
{
  while (*wrapper<parameter->leftcolumn) {
    (*column)++;    
    *wrapper+=parameter->bigcolumn+1;
  }
  *wrapper-=parameter->leftcolumn;
}

void putitem(int column, int line, SONGTYPE *song, int color, 
             PARAMETERTYPE *parameter)
/* puts a menu item in the color desired */
/* leaves cursor around */
{
  column++;
  if (parameter->verbose) {
    mycputs(parameter,column,line,song->diskname,color);
    column+=DISKNAMELENGTH+1;
    mycputs(parameter,column,line,song->score,color);
    column+=SCORELENGTH+1;
  }
  if (parameter->verbose || parameter->DOS) {
    mycputs(parameter,column,line,song->DOSname,color);
    column+=DOSNAMELENGTH+1;
  }
  if (parameter->verbose || !parameter->DOS)
    mycputs(parameter,column,line,song->songname,color);
}

void getbig(SONGSTYPE *songs, PARAMETERTYPE *parameter, int *bcolumn, 
            int *bline)
/* finds the coordinates of the current song in the menu window */
{
  *bcolumn=(songs->songcurrent-1)/parameter->hugeline+1;
  *bline=songs->songcurrent-songs->songcorner-
         (*bcolumn-1)*parameter->hugeline+1;
}

int getmouseptr(SONGSTYPE *songs, PARAMETERTYPE *parameter, 
                MOUSETYPE *mousedata)
/* finds the closest song name to the mouse cursor */
{
  int oldcolumn,column,halfcolumn,wrapper;
  int bline,bcolumn; 
  int songlimit;
  int mouseptr;

  bline=mousedata->y-2;
  if (bline<1) bline=1;
  else 
    if (bline>parameter->bigline) bline=parameter->bigline;
  column=3;
  wrapper=0;
  bcolumn=1;
  cleverwrapper(parameter,&wrapper,&column);
  column+=parameter->itemlength;
  oldcolumn=column;
  cleverwrapper(parameter,&wrapper,&column);
  halfcolumn=(column+oldcolumn)/2;
  while (halfcolumn<=mousedata->x) {
    column+=parameter->itemlength;
    oldcolumn=column;
    cleverwrapper(parameter,&wrapper,&column);
    halfcolumn=(column+oldcolumn)/2;
    bcolumn++;
  }
  if (bcolumn>parameter->bigcolumn) bcolumn=parameter->bigcolumn;
  songlimit=bcolumn*parameter->hugeline;
  mouseptr=songs->songcorner+(bcolumn-1)*parameter->hugeline+bline-1;
  if (mouseptr>songlimit) mouseptr=songlimit;
  if (mouseptr>songs->songnumber) mouseptr=songs->songnumber;
  return(mouseptr);
}

void putcurrent(SONGSTYPE *songs, PARAMETERTYPE *parameter, int color)
/* puts the current song in the color desired */
/* leaves cursor around */
{
  int line,column; /* screen coordinates */
  int wrapper; /* used for clever column spacing */
  int bline,bcolumn;

  getbig(songs,parameter,&bcolumn,&bline);
  line=bline+2;
  column=3;
  wrapper=0;
  cleverwrapper(parameter,&wrapper,&column);
  while (--bcolumn>0) {
    column+=parameter->itemlength;
    cleverwrapper(parameter,&wrapper,&column);
  }
  putitem(column,line,&(songs->song[songs->songcurrent]),color,parameter);
}

void unputcurrent(SONGSTYPE *songs, PARAMETERTYPE *parameter)
/* unputs the current song */
/* leaves cursor around */
{
  if (songs->song[songs->songcurrent].picked!=0) 
    putcurrent(songs,parameter,colorpicked|colorborder);
  else
    putcurrent(songs,parameter,coloritem|colorborder);
}

void changecurrent(SONGSTYPE *songs, PARAMETERTYPE *parameter, 
                   MOUSETYPE *mousedata, int songptr)
/* changes the current song and updates the menu window */
/* moves away cursor */
{
  int mouseptr,intheway;

  if (songs->songcurrent!=songptr) {
    if (parameter->mouse) { 
      mouseptr=getmouseptr(songs,parameter,mousedata);
      intheway=((mouseptr==songptr) || (mouseptr==songs->songcurrent)); 
    }
    else intheway=FALSE;
    if (intheway)
      mousehide(mousedata->x,mousedata->y,mousedata->c,mousedata->color);
    unputcurrent(songs,parameter);
    songs->songcurrent=songptr;
    if (songs->song[songptr].picked!=0) 
      putcurrent(songs,parameter,colorpicked|colorcurrent);
    else
      putcurrent(songs,parameter,coloritem|colorcurrent);
    if (intheway)
      mouseshow(mousedata->x,mousedata->y,&(mousedata->c),&(mousedata->color));
    movecursor(parameter);
  }
  else bellit();
}

void printarrows(SONGSTYPE *songs, PARAMETERTYPE *parameter)
/* displays PgUp and PgDn */
/* moves away cursor */
{
  int column;

  if (songs->songcorner>1)
    mycputs(parameter,parameter->maxcolumn-strlen(PGUP),1,PGUP,
            coloroutline|colorborder);
  else
    for (column=1 ; column<=strlen(PGUP) ; column++)
      mycputs(parameter,parameter->maxcolumn-column,1,"Ä",
              coloroutline|colorborder);
  if ((songs->songcorner+parameter->bigline-1)<parameter->hugeline)
   mycputs(parameter,parameter->maxcolumn-strlen(PGDN),parameter->maxline,PGDN,
           coloroutline|colorborder);
  else
    for (column=1 ; column<=strlen(PGUP) ; column++)
      mycputs(parameter,parameter->maxcolumn-column,parameter->maxline,"Ä",
              coloroutline|colorborder);
  movecursor(parameter);
}

void printsongs(SONGSTYPE *songs, PARAMETERTYPE *parameter, 
                MOUSETYPE *mousedata)
/* displays all the menu items and PgUp-PgDn */
/* moves away cursor */
{
  int bline,bcolumn; /* item coordinates */
  int line,column; /* screen coordinates */
  int songptr,songlimit;
  int wrapper; /* used for clever column spacing */

  if (parameter->mouse)
    mousehide(mousedata->x,mousedata->y,mousedata->c,mousedata->color);
  wrapper=0;
  column=3;
  songlimit=parameter->hugeline;
  for (bcolumn=1 ; bcolumn<=parameter->bigcolumn ; bcolumn++) {
    songptr=songs->songcorner+(bcolumn-1)*parameter->hugeline;
    cleverwrapper(parameter,&wrapper,&column);
    for (line=3 , bline=1 ; bline<=parameter->bigline ; line++ , bline++)
      if (songptr<=songlimit)
        if (songptr==songs->songcurrent) 
          if (songs->song[songptr].picked!=0)
            putitem(column,line,&(songs->song[songptr++]),
                    colorpicked|colorcurrent,parameter);
          else
            putitem(column,line,&(songs->song[songptr++]),
                    coloritem|colorcurrent,parameter);
        else 
          if (songs->song[songptr].picked!=0)
            putitem(column,line,&(songs->song[songptr++]),
                    colorpicked|colorborder,parameter);
          else
            putitem(column,line,&(songs->song[songptr++]),
                    coloritem|colorborder,parameter);
      else
        putitem(column,line,&(songs->song[0]),coloritem|colorborder,parameter);
    column+=parameter->itemlength;
    songlimit+=parameter->hugeline;
    /* small check for the last menu item column sometime incomplete */
    if (songlimit>songs->songnumber) songlimit=songs->songnumber;
  }
  if (parameter->mouse)
    mouseshow(mousedata->x,mousedata->y,&(mousedata->c),&(mousedata->color));
  printarrows(songs,parameter);
}

void dopgup(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int bcolumn,bline; 

  if (songs->songcorner>1) {
    /* move up half a screen */
    songs->songcorner-=parameter->bigline/2;
    /* make sure upper-left item exists */
    if (songs->songcorner<1) songs->songcorner=1;
    /* make sure current song is on the screen */
    getbig(songs,parameter,&bcolumn,&bline);
    if (bline>parameter->bigline) songs->songcurrent=songs->songcorner;
    printsongs(songs,parameter,mousedata);
  }
  else 
    /* can't scroll */
    changecurrent(songs,parameter,mousedata,1);
}

void dopgdn(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int bcolumn,bline; 

  if ((songs->songcorner+parameter->bigline-1)<parameter->hugeline) {
    /* move down half a screen */
    songs->songcorner+=parameter->bigline/2;
    /* no need to make sure upper-left item exists, it always does */
    /* make sure current song is on the screen */
    getbig(songs,parameter,&bcolumn,&bline);
    if (bline<1) songs->songcurrent=songs->songcorner;
    printsongs(songs,parameter,mousedata);
  }
  else 
    /* can't scroll */
    changecurrent(songs,parameter,mousedata,songs->songnumber);
}

void doleft(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;

  songptr=songs->songcurrent-parameter->hugeline;
  if (songptr>=1) changecurrent(songs,parameter,mousedata,songptr);
  else bellit();
}

void doright(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;

  songptr=songs->songcurrent+parameter->hugeline;
  if (songptr<=songs->songnumber)
    changecurrent(songs,parameter,mousedata,songptr);
  else bellit();
}

void doup(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int wrapper; /* used for clever column spacing */
  int bcolumn,bline;
  int songlimit; /* first song of current column */
  int songptr,column;

  getbig(songs,parameter,&bcolumn,&bline);
  songlimit=parameter->hugeline*(bcolumn-1)+1;
  if (bline==1) {
    /* goes off screen */
    if (songs->songcurrent==songlimit)
      /* can't scroll vertically */
      bellit();
    else {
      /* can scroll vertically */
      if (parameter->mouse)
        mousehide(mousedata->x,mousedata->y,mousedata->c,mousedata->color);
      unputcurrent(songs,parameter);
      myscrolldown(parameter);
      songs->songcorner--;
      songs->songcurrent--;
      wrapper=0;
      column=3;
      songptr=songs->songcorner;
      cleverwrapper(parameter,&wrapper,&column);
      for (bcolumn=1 ; bcolumn<=parameter->bigcolumn ; bcolumn++) {
        if (songptr==songs->songcurrent) 
          if (songs->song[songptr].picked!=0) 
            putitem(column,3,&(songs->song[songptr]),
                    colorpicked|colorcurrent,parameter);
          else
            putitem(column,3,&(songs->song[songptr]),
                    coloritem|colorcurrent,parameter);
        else
          if (songs->song[songptr].picked!=0)
            putitem(column,3,&(songs->song[songptr]),
                    colorpicked|colorborder,parameter);
          else
            putitem(column,3,&(songs->song[songptr]),
                    coloritem|colorborder,parameter);
        songptr+=parameter->hugeline;
        if (songptr>songs->songnumber) break; /* unlikely though for up move */
        column+=parameter->itemlength;
        cleverwrapper(parameter,&wrapper,&column);
      }
      if (parameter->mouse)
        mouseshow(mousedata->x,mousedata->y,&(mousedata->c),
                  &(mousedata->color));
      printarrows(songs,parameter);
    }
  }
  else
    /* stays on screen */
    changecurrent(songs,parameter,mousedata,(songs->songcurrent-1));
}

void dodown(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int wrapper; /* used for clever column spacing */
  int bline,bcolumn;
  int songlimit; /* last song of current column */
  int songptr,column;

  getbig(songs,parameter,&bcolumn,&bline);
  songlimit=parameter->hugeline*bcolumn;
  if (songlimit>songs->songnumber) songlimit=songs->songnumber;
  if (bline==parameter->bigline) {
    /* goes off screen */
    if (songs->songcurrent==songlimit)
      /* can't scroll vertically */
      bellit();
    else {
      /* can scroll vertically */
      if (parameter->mouse)
        mousehide(mousedata->x,mousedata->y,mousedata->c,mousedata->color);
      unputcurrent(songs,parameter);
      myscrollup(parameter);
      songs->songcorner++;
      songs->songcurrent++;
      wrapper=0;
      column=3;
      songptr=songs->songcorner+parameter->bigline-1;
      cleverwrapper(parameter,&wrapper,&column);
      for (bcolumn=1 ; bcolumn<=parameter->bigcolumn ; bcolumn++) {
        if (songptr<=songs->songnumber)
          if (songptr==songs->songcurrent) 
            if (songs->song[songptr].picked!=0) 
              putitem(column,parameter->maxline-2,&(songs->song[songptr]),
                      colorpicked|colorcurrent,parameter);
            else
              putitem(column,parameter->maxline-2,&(songs->song[songptr]),
                      coloritem|colorcurrent,parameter);
          else
            if (songs->song[songptr].picked!=0)
              putitem(column,parameter->maxline-2,&(songs->song[songptr]),
                      colorpicked|colorborder,parameter);
            else
              putitem(column,parameter->maxline-2,&(songs->song[songptr]),
                      coloritem|colorborder,parameter);
        songptr+=parameter->hugeline;
        if (songptr>songs->songnumber) break; /* likely for down move */
        column+=parameter->itemlength;
        cleverwrapper(parameter,&wrapper,&column);
      }
      if (parameter->mouse)
        mouseshow(mousedata->x,mousedata->y,&(mousedata->c),
                  &(mousedata->color));
      printarrows(songs,parameter);
    }
  }
  else 
    /* stays on screen */
    if (songs->songcurrent<songlimit) 
      changecurrent(songs,parameter,mousedata,(songs->songcurrent+1));
    else bellit();
}

void dohome(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int bcolumn,bline; 

  if (songs->songcorner!=1) {
    songs->songcorner=1;
    /* make sure current song is on the screen */
    getbig(songs,parameter,&bcolumn,&bline);
    if (bline>parameter->bigline) songs->songcurrent=1;
    printsongs(songs,parameter,mousedata);
  }
  else
    /* can't scroll */
    changecurrent(songs,parameter,mousedata,1);
}

void doend(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int bcolumn,bline; 

  if (songs->songcorner!=(parameter->hugeline-parameter->bigline+1)) {
    songs->songcorner=parameter->hugeline-parameter->bigline+1;
    /* make sure current song is on the screen */
    getbig(songs,parameter,&bcolumn,&bline);
    if (bline<1) songs->songcurrent=songs->songnumber;
    printsongs(songs,parameter,mousedata);
  }
  else
    /* can't scroll */
    changecurrent(songs,parameter,mousedata,songs->songnumber);
}

void doatslash(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;

  songs->songpriority=0;
  /* use current menu item as a basis for reversing statuses */
  if (songs->song[songs->songcurrent].picked!=0)
    for (songptr=1 ; songptr<=songs->songnumber ; songptr++)
      songs->song[songptr].picked=0;
  else
    for (songptr=1 ; songptr<=songs->songnumber ; songptr++)
      songs->song[songptr].picked=++songs->songpriority;
  printsongs(songs,parameter,mousedata);
}

void dostar(SONGSTYPE *songs) 
{ 
  int songptr,songlimit,songnext,songsearch;

  if (songs->songpriority==0) bellit();
  else {
    songs->songpriority=0;
    for (songptr=1 ; songptr<=songs->songnumber ; songptr++)
      if (songs->song[songptr].picked!=0) {
        songs->songpriority++;
        songs->song[songptr].picked=-1;
      }
    for (songlimit=songs->songpriority ; songlimit>=1 ; songlimit--) {
      songnext=1+(rand() % songlimit);
      songsearch=0;
      for (songptr=1 ; songptr<=songnext ; songptr++) {
        songsearch++;
        while (songs->song[songsearch].picked>=0) songsearch++;
      }
      songs->song[songsearch].picked=songlimit;
    }
  }
}

void dospgup(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;

  songptr=songs->songcorner+(parameter->bigcolumn-1)*parameter->hugeline;
  changecurrent(songs,parameter,mousedata,songptr);
}

void dospgdn(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;

  songptr=songs->songcorner+(parameter->bigcolumn-1)*parameter->hugeline+
          parameter->bigline-1;
  if (songptr>songs->songnumber) songptr=songs->songnumber;
  changecurrent(songs,parameter,mousedata,songptr);
}

void dosleft(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;
  int bline,bcolumn;

  getbig(songs,parameter,&bcolumn,&bline);
  songptr=songs->songcorner+bline-1;
  changecurrent(songs,parameter,mousedata,songptr);
}

void dosright(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;
  int bline,bcolumn;

  getbig(songs,parameter,&bcolumn,&bline);
  songptr=songs->songcorner+(parameter->bigcolumn-1)*parameter->hugeline+
          bline-1;
  if (songptr>songs->songnumber) songptr-=parameter->hugeline;
  changecurrent(songs,parameter,mousedata,songptr);
}

void dosup(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;
  int bline,bcolumn;

  getbig(songs,parameter,&bcolumn,&bline);
  songptr=songs->songcorner+(bcolumn-1)*parameter->hugeline;
  changecurrent(songs,parameter,mousedata,songptr);
}

void dosdown(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;
  int bline,bcolumn;

  getbig(songs,parameter,&bcolumn,&bline);
  songptr=songs->songcorner+(bcolumn-1)*parameter->hugeline+
          parameter->bigline-1;
  if (songptr>(parameter->hugeline*bcolumn)) 
    songptr=parameter->hugeline*bcolumn;
  if (songptr>songs->songnumber) songptr=songs->songnumber;
  changecurrent(songs,parameter,mousedata,songptr);
}

void doshome(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  changecurrent(songs,parameter,mousedata,songs->songcorner);
}

void dosend(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr;

  songptr=songs->songcorner+parameter->bigline-1;
  if (songptr>parameter->hugeline) songptr=parameter->hugeline;
  changecurrent(songs,parameter,mousedata,songptr);
}

void doscenter(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int songptr,songlimit;
  int bcolumn;

  bcolumn=(parameter->bigcolumn+1)/2;
  songptr=songs->songcorner+parameter->hugeline*(bcolumn-1);
  songlimit=songptr+parameter->bigline-1;
  if (songlimit>(parameter->hugeline*bcolumn)) 
    songlimit=parameter->hugeline*bcolumn;
  songptr=(songptr+songlimit)/2;
  changecurrent(songs,parameter,mousedata,songptr);
}

void dospace(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int intheway,mouseptr;

  if (parameter->mouse) { 
    mouseptr=getmouseptr(songs,parameter,mousedata);
    intheway=(mouseptr==songs->songcurrent);
  }
  else intheway=FALSE;
  if (intheway)
    mousehide(mousedata->x,mousedata->y,mousedata->c,mousedata->color);
  if (songs->song[songs->songcurrent].picked!=0) {
    songs->song[songs->songcurrent].picked=0;
    putcurrent(songs,parameter,coloritem|colorcurrent);
  }
  else {
    songs->song[songs->songcurrent].picked=++songs->songpriority;
    putcurrent(songs,parameter,colorpicked|colorcurrent);
  }
  if (intheway)
    mouseshow(mousedata->x,mousedata->y,&(mousedata->c),&(mousedata->color));
  movecursor(parameter);
}

void domspace(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int mouseptr,tempcurrent;

  mouseptr=getmouseptr(songs,parameter,mousedata);
  mousehide(mousedata->x,mousedata->y,mousedata->c,mousedata->color);
  if (songs->song[mouseptr].picked!=0) 
    songs->song[mouseptr].picked=0;
  else 
    songs->song[mouseptr].picked=++songs->songpriority;
  if (mouseptr==songs->songcurrent)
    if (songs->song[mouseptr].picked!=0) 
      putcurrent(songs,parameter,colorpicked|colorcurrent);
    else 
      putcurrent(songs,parameter,coloritem|colorcurrent);
  else {
    tempcurrent=songs->songcurrent;
    songs->songcurrent=mouseptr;
    if (songs->song[mouseptr].picked!=0) 
      putcurrent(songs,parameter,colorpicked|colorborder);
    else 
      putcurrent(songs,parameter,coloritem|colorborder);
    songs->songcurrent=tempcurrent;
  }
  mouseshow(mousedata->x,mousedata->y,&(mousedata->c),&(mousedata->color));
  movecursor(parameter);
}

void domup(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int wrapper; /* used for clever column spacing */
  int bcolumn,bline;
  int songptr,column;
  struct time timep;
  int time,oldtime;

  if (songs->songcorner!=1) {
    gettime(&timep);
    oldtime=((int)timep.ti_hund)+100*((int)timep.ti_sec);
    mousehide(mousedata->x,mousedata->y,mousedata->c,mousedata->color);
    getbig(songs,parameter,&bcolumn,&bline);
    if (bline==parameter->bigline) {
      unputcurrent(songs,parameter);
      songs->songcurrent--;
    }
    songs->songcorner--;
    myscrolldown(parameter);
    if (bline==parameter->bigline)
      if (songs->song[songs->songcurrent].picked!=0)
        putcurrent(songs,parameter,colorpicked|colorcurrent);
      else
        putcurrent(songs,parameter,coloritem|colorcurrent);
    wrapper=0;
    column=3;
    songptr=songs->songcorner;
    cleverwrapper(parameter,&wrapper,&column);
    for (bcolumn=1 ; bcolumn<=parameter->bigcolumn ; bcolumn++) {
      if (songptr==songs->songcurrent) 
        if (songs->song[songptr].picked!=0) 
          putitem(column,3,&(songs->song[songptr]),
                  colorpicked|colorcurrent,parameter);
        else
          putitem(column,3,&(songs->song[songptr]),
                  coloritem|colorcurrent,parameter);
      else
        if (songs->song[songptr].picked!=0)
          putitem(column,3,&(songs->song[songptr]),
                  colorpicked|colorborder,parameter);
        else
          putitem(column,3,&(songs->song[songptr]),
                  coloritem|colorborder,parameter);
      songptr+=parameter->hugeline;
      if (songptr>songs->songnumber) break; /* unlikely though for up move */
      column+=parameter->itemlength;
      cleverwrapper(parameter,&wrapper,&column);
    }
    mouseshow(mousedata->x,mousedata->y,&(mousedata->c),&(mousedata->color));
    printarrows(songs,parameter);
    do {
      gettime(&timep);
      time=((int)timep.ti_hund)+100*((int)timep.ti_sec)-oldtime;
      if (time<0) time+=6000;
    } while (time<SCROLLDELAY);
  }
}

void domdown(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
{
  int wrapper; /* used for clever column spacing */
  int bline,bcolumn;
  int songptr,column;
  struct time timep;
  int time,oldtime;

  if ((songs->songcorner+parameter->bigline-1)<parameter->hugeline) {
    gettime(&timep);
    oldtime=((int)timep.ti_hund)+100*((int)timep.ti_sec);
    mousehide(mousedata->x,mousedata->y,mousedata->c,mousedata->color);
    getbig(songs,parameter,&bcolumn,&bline);
    if (bline==1) {
      unputcurrent(songs,parameter);
      songs->songcurrent++;
    }
    songs->songcorner++;
    myscrollup(parameter);
    if (bline==1) 
      if (songs->song[songs->songcurrent].picked!=0)
        putcurrent(songs,parameter,colorpicked|colorcurrent);
      else
        putcurrent(songs,parameter,coloritem|colorcurrent);
    wrapper=0;
    column=3;
    songptr=songs->songcorner+parameter->bigline-1;
    cleverwrapper(parameter,&wrapper,&column);
    for (bcolumn=1 ; bcolumn<=parameter->bigcolumn ; bcolumn++) {
      if (songptr<=songs->songnumber)
        if (songptr==songs->songcurrent) 
          if (songs->song[songptr].picked!=0) 
            putitem(column,parameter->maxline-2,&(songs->song[songptr]),
                    colorpicked|colorcurrent,parameter);
          else
            putitem(column,parameter->maxline-2,&(songs->song[songptr]),
                    coloritem|colorcurrent,parameter);
        else
          if (songs->song[songptr].picked!=0)
            putitem(column,parameter->maxline-2,&(songs->song[songptr]),
                    colorpicked|colorborder,parameter);
          else
            putitem(column,parameter->maxline-2,&(songs->song[songptr]),
                    coloritem|colorborder,parameter);
      songptr+=parameter->hugeline;
      if (songptr>songs->songnumber) break; /* likely for down move */
      column+=parameter->itemlength;
      cleverwrapper(parameter,&wrapper,&column);
    }
    mouseshow(mousedata->x,mousedata->y,&(mousedata->c),&(mousedata->color));
    printarrows(songs,parameter);
    do {
      gettime(&timep);
      time=((int)timep.ti_hund)+100*((int)timep.ti_sec)-oldtime;
      if (time<0) time+=6000;
    } while (time<SCROLLDELAY);
  }
}

int picksongs(SONGSTYPE *songs, PARAMETERTYPE *parameter, MOUSETYPE *mousedata)
/* updates the menu */
{

  songs->songpriority=0;
  do {
    if (bioskey(1))
      switch (bioskey(0)) {
        case KEYESC:return(TRUE);
        case KEYENTER:return(FALSE);
        case KEYSPACE:dospace(songs,parameter,mousedata);
                      break;
        case KEYPGUP:dopgup(songs,parameter,mousedata);
                     break;
        case KEYPGDN:dopgdn(songs,parameter,mousedata);
                     break;
        case KEYLEFT:doleft(songs,parameter,mousedata);
                     break;
        case KEYRIGHT:doright(songs,parameter,mousedata);
                      break;
        case KEYUP:doup(songs,parameter,mousedata);
                   break;
        case KEYDOWN:dodown(songs,parameter,mousedata);
                     break;
        case KEYHOME:dohome(songs,parameter,mousedata);
                     break;
        case KEYEND:doend(songs,parameter,mousedata);
                    break;
        case KEYATSLASH:doatslash(songs,parameter,mousedata);
                        break;
        case KEYSTAR1:dostar(songs);
                      break;
        case KEYSTAR2:dostar(songs);
                      break;
        case SKEYPGUP:dospgup(songs,parameter,mousedata);
                      break;
        case SKEYPGDN:dospgdn(songs,parameter,mousedata);
                      break;
        case SKEYLEFT:dosleft(songs,parameter,mousedata);
                      break;
        case SKEYRIGHT:dosright(songs,parameter,mousedata);
                       break;
        case SKEYUP:dosup(songs,parameter,mousedata);
                    break;
        case SKEYDOWN:dosdown(songs,parameter,mousedata);
                      break;
        case SKEYHOME:doshome(songs,parameter,mousedata);
                      break;
        case SKEYEND:dosend(songs,parameter,mousedata);
                     break;
        case SKEYCENTER:doscenter(songs,parameter,mousedata);
                        break;
        default:bellit();
                break;
      } 
    else
      if (parameter->mouse)
        switch (readmouse(songs,parameter,mousedata)) {
          case KEYESC:return(TRUE);
          case KEYENTER:return(FALSE);
          case KEYSPACE:domspace(songs,parameter,mousedata);
                        break;
          case KEYUP:domup(songs,parameter,mousedata);
                     break;
          case KEYDOWN:domdown(songs,parameter,mousedata);
                       break;
          default:break;
        }
  } while (TRUE);
}
