/* -*-C-*- eopact.h */
/*-->eopact*/
/**********************************************************************/
/******************************* eopact *******************************/
/**********************************************************************/

#define MAXFRAC	 8		/* maximum fractional step divisor */
#define MINFRAC 64		/* minimum fractional step divisor */
#define DIGVAL(c) (INT16)(c - '0')

static void unload_fonts();	/* private routine to unload fonts on zoom */

void
eopact()			/* end-of-page action */
{
    int loop_count;		/* loop count */
    INT16 np;			/* input page number */
    BOOLEAN show_page;		/* page redisplay flag */
    char tc;			/* temporary character */

    /*
    Screen positioning control is done by obvious mnemonics given in the
    menu bar displayed	by   bopact(), but cursor keys	 and  EMACS-like
    control keys are also recognized.  Keyboard input causes  an instant
    end-of-page action, to  facilitate	 rapid page  repositioning,  and
    skimming through a document.  All  available commands are acted upon
    before   screen display   is   reattempted.	  This	 makes	repeated
    positioning commands cumulative.
    */

    if (!quiet)
	OUTS(BELLS);		/* wake up the user */
    (void)fflush(plotfp);	/* make sure display is up-to-date */

    loop_count = 1;
    show_page = FALSE;
    while ((loop_count-- > 0) || kbinput())
    {
	tc = (char)kbget();
	if (tc == '\033')	/* ESC sequence--function key */
	{
	    /* Expect ESC x, ESC O x or ESC [ x (x = A,B,C,D) */
	    tc = (char)kbget();
	    if ((tc == '[') || (tc == 'O'))
		tc = (char)kbget();
	    switch(tc)
	    {
	    case 'A':		/* cursor up */
		tc = 'u';
		break;
	    case 'B':		/* cursor down */
		tc = 'd';
		break;
	    case 'C':		/* cursor right */
		tc = 'r';
		break;
	    case 'D':		/* cursor left */
		tc = 'l';
		break;
	    case 'V':		/* META-V -- previous page */
	    case 'v':
		tc = 'P';
		break;
	    default:		/* none of these--accept it anyway */
		break;
	    }
	}
	switch (tc)
	{
	case '0':		/* goto n-th page (recursively) */
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	    np = DIGVAL(tc);
	    for (tc = (char)kbget(); ;tc = (char)kbget())
	    {
	       if (isdigit(tc))
		   np = 10*np + DIGVAL(tc);
	       else if ((tc == '\177') || (tc == '\b'))
		   np /= 10;	/* rubout last digit */
	       else
		   break;
	    }
	    np = MIN(np,page_count); /* big numbers go to last page */
	    if (np > 0)		/* got a page number */
	    {
		cur_index = np - 1;
		show_page = TRUE; /* out-of-sequence page */
	    }
	    else
		show_page = FALSE;
	    continue;

	case ' ':		/* normal case - start next page */
	case '\026':		/* CTL-V */
	case '\r':
	case '\n':
	case '\0':
	    show_page = FALSE;
	    continue;

	case '\f':		/* redisplay current page  */
	case '.':
	    show_page = TRUE;
	    continue;

	case '@':		/* reset to initial state */
	    xscreen = 0;	/* 'i' is mnemonic, but too close to 'u' */
	    yscreen = 0;	/* on keyboard */
	    show_page = TRUE;
	    continue;

	case 'd':		/* move down and redisplay  */
	case '\016':	/* CTL-N */
	    yscreen -= (YSIZE/MINFRAC);
	    show_page = TRUE;
	    continue;

	case 'D':
	    yscreen -= (YSIZE/MAXFRAC);
	    show_page = TRUE;
	    continue;

	case 'l':		/* move left and redisplay */
	case '\002':		/* CTL-B */
	    xscreen -= (XSIZE/MINFRAC);
	    show_page = TRUE;
	    continue;

	case 'L':
	    xscreen -= (XSIZE/MAXFRAC);
	    show_page = TRUE;
	    continue;

	case 'p':		/* redisplay from previous page */
	case 'P':
	case '\b':
	case '^':
	    if (cur_index > 0)
	    {
		cur_index--;
		show_page = TRUE;
	    }
	    else		/* no previous page--ignore */
	    {
		OUTS(BELLS);
		loop_count = 1;
		show_page = FALSE;
	    }
	    continue;

	case 'q':		/* quit */
	case 'Q':
	case 'x':		/* exit */
	case 'X':
	case '\003':		/* CTL-C */
	case '\031':		/* CTL-Y */
	    (void)devterm();	/* terminate device output */
	    (void)dviterm();	/* terminate DVI file processing */
	    (void)alldone();	/* this does not return */
	    continue;

	case 'r':		/* move right and redisplay */
	case '\006':		/* CTL-F */
	    xscreen += (XSIZE/MINFRAC);
	    show_page = TRUE;
	    continue;

	case 'R':
	    xscreen += (XSIZE/MAXFRAC);
	    show_page = TRUE;
	    continue;

	case 'u':		/* move up and redisplay */
	case '\020':		/* CTL-P */
	    yscreen += (YSIZE/MINFRAC);
	    show_page = TRUE;
	    continue;

	case 'U':
	    yscreen += (YSIZE/MAXFRAC);
	    show_page = TRUE;
	    continue;

	case 'z':		/* zoom down one magstep (1.2) */
	    runmag = MAGSIZE(actfact((UNSIGN32)((5*runmag)/6)));
	    conv = ((float)num/(float)den) *
		((float)runmag/(float)STDMAG) *

#if    USEGLOBALMAG
		actfact(mag) *
#endif

		((float)RESOLUTION/254000.0);
	    (void)unload_fonts();
	    show_page = TRUE;
	    continue;

	case 'Z':		/* zoom up one magstep (1.2) */
	    runmag = MAGSIZE(actfact((UNSIGN32)((runmag*6)/5)));
	    conv = ((float)num/(float)den) *
		((float)runmag/(float)STDMAG) *

#if    USEGLOBALMAG
		actfact(mag) *
#endif

		((float)RESOLUTION/254000.0);
	    (void)unload_fonts();
	    show_page = TRUE;
	    continue;

	default:		/* unimplemented command */
	    OUTS(BELLS);	/* beep to flag ignored input */
	    (void)kbflush();	/* clear any typeahead */
	    show_page = FALSE;
	    loop_count = 1;
	    continue;		/* stay in read-loop */}
    }
    if (show_page)
	(void)prtpage(page_ptr[cur_index]);
}

static void
unload_fonts()			/* mark all fonts as not loaded */
{				/* and set no current fonts */
    INT16 k;

    for (fontptr = hfontptr; fontptr != (struct font_entry *)NULL;
	 fontptr = fontptr->next)
    {
	for (k = 0; k < NPXLCHARS; ++k)
	    fontptr->ch[k].isloaded = FALSE;

	if (fontptr->font_file_id != (FILE*)NULL)
	{
	    (void)fclose(fontptr->font_file_id);
	    fontptr->font_file_id = (FILE*)NULL;
	}
    }

    fontfp = (FILE*)NULL;		/* no current font file */
    for ( ; nopen > 0; --nopen)		/* clear font file cache */
    {
	font_files[nopen].font_id = (FILE*)NULL;
	font_files[nopen].use_count = (INT16)0;
    }

    /* NB: It is important here that the loop index be global; the relation
    of fontptr to pfontptr is used by openfont() to decide whether the font
    file is already open. */
    for (fontptr = hfontptr; fontptr != (struct font_entry *)NULL;
	 fontptr = fontptr->next)
    {
	pfontptr = (struct font_entry *)(NULL); /* so reldfont() calls openfont() */
	(void)reldfont(fontptr);	/* get new font metrics */
    }
}
