/*--------------------------------------------------------------------------
    Complete listing for a desk accessory/program for controlling
    an NEC P6+ printer by Les Kneeling, June 1990.

    To run as a program rename the file P6+.PRG, to run as an accessory
    rename the file P6+.ACC, calling the file anything else will make it
    a program not an accessory.
----------------------------------------------------------------------------*/
#include <obdefs.h>                  /* Include files                       */
#include <gemdefs.h>
#include <osbind.h>
#include <stdio.h>

#include "p6+.h"                     /* Resource details                    */

#define FALSE 0                      /* Convenient defines                  */
#define TRUE 1
#define UP 1
#define DOWN -1
#define L_ARROW 4
#define R_ARROW 3

extern gl_apid;

struct{                              /* Struct for sys information          */
    char font;
    char pitch;
    char length;
    char lpi;
    char margin;
    char just;
    char tab;
    } current = { 0, 0, 69, 6, 0, 0, 10 };
                                    /* Initialise to default values         */
FILE *stream;

                                    /* Bit maps for allowable pitches       */

char font_pitches[8] = {    3,         /* 00011     Courier        */
                            2,         /* 00010     Prestige       */
                            1,         /* 00001     Souvenir       */
                            8,         /* 01000     Bold PS        */
                            8,         /* 01000     Times          */
                            8,         /* 01000     Helvette       */
                            7,         /* 00111     Draft          */
                            16         /* 10000     Fontcard       */
                        };             /* ||||\                    */
                                       /* |||\ 10 cpi              */
                                       /* ||\ 12 cpi               */
                                       /* |\ High speed            */
                                       /* \ Proportional           */
                                       /*   Unknown                */

char fonts[8][9] =   {               /* Names of fonts                      */
                    "Courier",
                    "Prestige",
                    "Souvenir",
                    "Bold PS",
                    "Times",
                    "Helvette",
                    "Draft",
                    "FontCard"
                    };

char pitch[8][3] =    { "10", "12", "HS", "PS", "??" };
                                     /* Text for pitches                    */
OBJECT *dialog, *warning;            /* Resource pointers                   */

char sys_file[18] = "C:\\p6+.sys";

int x, y, w, h, menu_id;
int error = FALSE;
int ACCESSORY = FALSE;               /* Listing executes as a program if
                                        FALSE or as an accessory if TRUE    */

main()                               /* Program starts here                 */
{
int event, finished = FALSE;
int message[8];

appl_init();                          /* Initialise ROMs                    */
get_operation_mode();                 /* Is the listing to work as an
                                         accessory or a program?            */
if( rsrc_load("P6+.RSC") )            /* Load resource                      */
    {
    rsrc_gaddr( 0, DIALOG, &dialog );
	*sys_file = Dgetdrv() + 'A';
    load_info();                      /* Get sys information                */
    initialise_resource();            /* Set up initial values in dialog    */
    if( ACCESSORY )                   /* Execute as an accessory            */
        {
        menu_id = menu_register(gl_apid, "  P6+");
                                      /* Put name in menu bar               */
        do    {
            event = evnt_mesag( message );
                                       /* Wait for accessory to be called   */
            wind_update( BEG_UPDATE ); /* Tell GEM accessory is working     */
            if( message[0] == AC_OPEN )/* If accessory is called            */
                finished = interact(); /* deal with interaction             */
            wind_update( END_UPDATE ); /* Tell GEM accessory is finished    */
            }while( TRUE );            /* Accessories execute 'forever'     */
        }
    else                               /* Execute as a program              */
        {
        graf_mouse( ARROW, 0l );       /* If the code is run as a program   */
                                       /* the desktop changes the mouse     */
                                       /* form to a bee, so it must be      */
                                       /* changed back to an arrow          */
        interact();                    /* Deal with interaction             */
        }
    }
else                                   /* If the resource file has not      */
    {                                  /* been found, say so and quit       */
    Cconws("Cannot find resource!");
    Frename( 0, "P6+.ACC", "P6+.ACX" );/* Stop accessory trying again       */
    Cconin();                          /* by renaming it                    */
    }
appl_exit();
}

get_operation_mode()                   /* Accessory or program              */
{
char name[160];                        /* Space for the path/filename       */
char command[160];                     /* There won't be a command line     */
                                       /* but just in case....              */
if( shel_read( name, command ) == 0 )  /* What is the name of               */
    {                                  /* the application?                  */
    Cconws("Who am I?");               /* It is not very likely that the    */
    Cconin();                          /* call will fail so this is not a   */
    exit(0);                           /* serious error message!            */
    }                                  /* Beware of using shel_read from    */
else                                   /* inside a 'shell' because it will  */
    {                                  /* return the name of the shell      */
    ACCESSORY = strcmp( name, "P6+.ACC" ) == 0;
    }                                  /* Set up the mode flag              */
}                                      /* default to program                */

initialise_resource()                  /* Set up the text in the objects    */
{
dialog[FONT_NAM].ob_spec = fonts[current.font];   /* The text in the        */
dialog[PITCH].ob_spec = pitch[current.pitch];     /* objects is created     */
dialog_print( PL, current.length );               /* directly, using a      */
dialog[LPI].ob_spec[0] = current.lpi + '0';       /* sprintf call adds      */
dialog_print( LM, current.margin );               /* about 3k to the        */
dialog_print( TAB, current.tab );                 /* program!               */

switch( current.just )
    {
    case 0:
            dialog[JUST].ob_spec[0] = L_ARROW;    /* Left justify           */
            dialog[JUST].ob_spec[1] = L_ARROW;
            break;
    case 1:
            dialog[JUST].ob_spec[0] = R_ARROW;    /* Center                 */
            dialog[JUST].ob_spec[1] = L_ARROW;
            break;
    case 2:
            dialog[JUST].ob_spec[0] = R_ARROW;    /* Right justify          */
            dialog[JUST].ob_spec[1] = R_ARROW;
            break;
    case 3:
            dialog[JUST].ob_spec[0] = L_ARROW;    /* Full out               */
            dialog[JUST].ob_spec[1] = R_ARROW;
            break;
    }
}

interact()                             /* Deal with the user actions        */
{
int event, finished = FALSE;

form_center( dialog, &x, &y, &w, &h ); /* Centre the dialog box             */
form_dial( FMD_START, 0, 0, 0, 0, x, y, w, h );
                                       /* Reserve screen area               */
draw( DIALOG, MAX_DEPTH );
                                       /* Show the dialog box               */
do    {
    event = form_do( dialog, 0 );      /* Handle interaction                */
    finished = handle_event( event );
    }while( !finished );
form_dial( FMD_FINISH, 0, 0, 0, 0, x, y, w, h );
                                       /* Restore screen area               */
return finished;
}

handle_event( event )                  /* Deal with user selection          */
int event;
{
int finished = FALSE;

error = FALSE;
switch( event )
    {
    case STYLE:     deselect(ENHANCED);
                    deselect(DOUBLE);
                    deselect(WIDE);
                    deselect(COND);
                    deselect(ITALIC);
                    draw( STYLE, 1 );
                    break;
    case FONT_NAM:  current.font = -1; /* <--- Notice that this line falls  */
    case FONT_UP:   do_font( UP );     /*      through to the next case,    */
                    break;             /*      this means that the variable */
    case FONT_DN:   do_font( DOWN );   /*      is preset and the code from  */
                    break;             /*      the next case is used to     */
    case PITCH:     current.pitch = -1;/*      draw the object - these      */
    case PITCH_UP:  do_pitch( UP );    /*      tricks are useful when       */
                    break;             /*      writing desk accessories     */
    case PITCH_DN:  do_pitch( DOWN );  /*      where space is at a premium  */
                    break;
    case PL:        current.length = 68;
    case PL_UP:     do_page_len( UP );
                    break;
    case PL_DN:     do_page_len( DOWN );
                    break;
    case LPI:       current.lpi = 8;
    case LPI_UP:
    case LPI_DN:    do_lpi();
                    break;
    case LM:        current.margin = -1;
    case LM_UP:     do_margin( UP );
                    break;
    case LM_DN:     do_margin( DOWN );
                    break;
    case JUST:      current.just = -1;
    case JUST_UP:   do_just( UP );
                    break;
    case JUST_DN:   do_just( DOWN );
                    break;
    case LINE_UP:   do_line_up();
                    break;
    case LINE_DN:   bprint( '\n' );
                    break;
    case TAB:       current.tab = 9;
    case TABUP:     do_tab( UP );
                    break;
    case TABDOWN:   do_tab( DOWN );
                    break;
    case FORMFEED:  bprint( 0x0c );
                    break;
    case RESET:     bprint( 27 );
                    bprint( 64 );
                    break;
    case INSTALL:   save_info();
                    deselect(INSTALL);
                    draw( INSTALL, 1 );
                    break;
    case PRINT:     do_settings();
                    if( error == FALSE )
                        print_file();
                    deselect(PRINT);
                    draw( PRINT, 1 );
                    break;
    case SET:       do_settings();
                    deselect(SET);
                    draw( SET, 1 );
                    break;
    case FINISHED:  finished = TRUE;
                    deselect(FINISHED);
                    draw( FINISHED, 1 );
                    break;
    }
return finished;
}

do_font( mode )                        /* Handle font change                */
int mode;
{
if( mode == UP )                       /* Increment font counter            */
    {
    if( current.font < 7 )
        current.font++;
    else
        current.font = 0;              /* Wrap around                       */
    }
else                                   /* Decrement font counter            */
    {
    if( current.font > 0 )
        current.font--;
    else
        current.font = 7;              /* Wrap around                       */
    }

dialog[FONT_NAM].ob_spec = fonts[current.font];
                                       /* Change text in object             */
draw( FONT_NAM, 0 );
                                       /* Show dialog box                   */
current.pitch = -1;
do_pitch( UP );                        /* Show lowest pitch                 */
}

do_pitch( mode )                       /* Handle pitch change               */
int mode;
{
int temp_pitch, found = FALSE;

if( mode == UP )                       /* Increment pitch                   */
    {
    temp_pitch = current.pitch;
    do    {                            /* Look for lowest valid pitch       */
        if( temp_pitch < 7 )
            temp_pitch++;
        else
            temp_pitch = 0;
        found = font_pitches[current.font] & 1 << temp_pitch;
                                       /* Test bit to see if pitch is valid */
        }while( !found );
    }
else                                   /* Decrement pitch                   */
    {
    temp_pitch = current.pitch;
    do    {                            /* Search bit map for first font     */
        if( temp_pitch > 0 )
            temp_pitch--;
        else
            temp_pitch = 7;
        found = font_pitches[current.font] & 1 << temp_pitch;
        }while( !found );
    }
current.pitch = temp_pitch;
dialog[PITCH].ob_spec = pitch[current.pitch];
                                       /* Alter text in object              */
draw( PITCH, 0 );
                                       /* and redraw it                     */
}

do_page_len( mode )                    /* Deal with page length change      */
int mode;
{
if( mode == UP )                       /* Maximum allowed is 99 lines       */
    if( current.length < 99 )
        current.length++;
    else
        current.length = 0;            /* Wrap around                       */
else
    if( current.length > 0 )
        current.length--;
    else
        current.length = 99;

dialog_print( PL, current.length );
                                       /* Update the object text            */
draw( PL, 0 );
                                       /* and redraw it                     */
}

do_lpi()                               /* Deal with lines per inch change   */
{
if( current.lpi == 6 )
    current.lpi = 8;
else
    current.lpi = 6;

dialog[LPI].ob_spec[0] = current.lpi + '0';
                                        /* Update the object text           */
draw( LPI, 0 );
                                        /* and redraw it                    */
}

do_margin( mode )                       /* deal with margin change          */
int mode;
{
if( mode == UP )                        /* Maximum allowed is 80            */
    if( current.margin < 80 )
        current.margin++;
    else
        current.margin = 0;
else
    if( current.margin > 0 )
        current.margin--;
    else
        current.margin = 80;

dialog_print( LM, current.margin );
                                        /* Update object text               */
draw( LM, 0 );                          /* and redraw it                    */
}

do_just( mode )                         /* Deal with change in justification*/
int mode;
{
if( mode == UP )                        /* Work out new value for           */
    if( current.just < 3 )              /* current_just                     */
        current.just++;
    else
        current.just = 0;
else
    if( current.just > 0 )
        current.just--;
    else
        current.just = 3;

switch( current.just )                  /* Change text in object            */
    {
    case 0:
            dialog[JUST].ob_spec[0] = L_ARROW;    /* Left justify           */
            dialog[JUST].ob_spec[1] = L_ARROW;
            break;
    case 1:
            dialog[JUST].ob_spec[0] = R_ARROW;    /* Full out               */
            dialog[JUST].ob_spec[1] = L_ARROW;
            break;
    case 2:
            dialog[JUST].ob_spec[0] = R_ARROW;    /* Right justify          */
            dialog[JUST].ob_spec[1] = R_ARROW;
            break;
    case 3:
            dialog[JUST].ob_spec[0] = L_ARROW;    /* Center                 */
            dialog[JUST].ob_spec[1] = R_ARROW;
            break;
    }
draw( JUST, 0 );                        /* Redraw object                    */
}

do_tab( mode )                          /* deal with tab change             */
int mode;
{
if( mode == UP )                        /* Maximum allowed is 10            */
    if( current.tab < 10 )
        current.tab++;
    else
        current.tab = 0;
else
    if( current.tab > 0 )
        current.tab--;
    else
        current.tab = 10;

dialog_print( TAB, current.tab );       /* Update object text               */
draw( TAB, 0 );                         /* and redraw it                    */
}

do_line_up()
{
bprint( 28 );                           /* Send code to printer to reverse  */                            
bprint( 82 );                           /* direction of line feed           */
bprint( '\n' );                         /* Do a line feed                   */
bprint( 28 );                           /* Set direction of line feed back  */
bprint( 70 );                           /* to normal                        */
}

do_settings()                           /* Deal with the 'passive'          */
{                                       /* selections made in the dialog    */
switch( current.font )
    {
    case 0:     bprint( 27 );           /* Courier                          */
                bprint( 107 );
                bprint( 0 );
                break;
    case 1:     bprint( 27 );           /* New Prestige Elite               */
                bprint( 107 );
                bprint( 19 );
                break;
    case 2:     bprint( 27 );           /* ITC Souvenir                     */
                bprint( 107 );
                bprint( 15 );
                break;
    case 3:     bprint( 27 );           /* Set Courier to clear the         */
                bprint( 107 );          /* previous LQ settings             */
                bprint( 0 );
                bprint( 27 );           /* Set proportional on - this       */
                bprint( 112 );          /* produces Bold P.S.               */
                bprint( 1 );
                break;
    case 4:     bprint( 27 );           /* Times                            */
                bprint( 107 );
                bprint( 18 );
                break;
    case 5:     bprint( 27 );           /* Helvette                         */
                bprint( 107 );
                bprint( 16 );
                break;
    case 6:     bprint( 27 );           /* Set Courier to clear the         */
                bprint( 107 );          /* previous LQ settings             */
                bprint( 0 );
                bprint( 27 );           /* Set proportional off - this      */
                bprint( 120 );          /* produces Draft                   */
                bprint( 0 );
                break;
    }

switch( current.pitch )
    {
    case 0:     bprint( 27 );           /* Proportional                     */
                bprint( 'P' );
                break;
    case 1:     bprint( 27 );           /* 12 cpi                           */
                bprint( 'M' );
                bprint( 28 );           /* Normal speed                     */
                bprint( 83 );
                bprint( 0 );
                break;
    case 2:     bprint( 27 );           /* 12 cpi                           */
                bprint( 'M' );
                bprint( 28 );           /* High speed                       */
                bprint( 83 );
                bprint( 1 );
                break;
    }

bprint( 27 );                           /* set page length in lines         */
bprint( 67 );
bprint( current.length );

if( current.lpi == 8 )                  /* set lines per inch               */
    {
    bprint( 27 );
    bprint( 48 );
    }
else
    {
    bprint( 27 );                       /* defaults to 6 lpi                */
    bprint( 40 );
    }

bprint( 27 );                           /* set left margin                  */
bprint( 108 );
bprint( current.margin );

bprint( 27 );                           /* set justification                */
bprint( 'a' );
bprint( current.just );

bprint( 27 );                           /* set tabs                         */
bprint( 'e' );
bprint( 48 );
bprint( current.tab );

bprint( 28 );                           /* set print height                 */
bprint( 86 );
bprint( ( dialog[DOUBLE].ob_state & SELECTED ) );

if( dialog[ENHANCED].ob_state & SELECTED )
    {                                   /* set/clear enhanced               */
    bprint( 27 );
    bprint( 'E' );
    }
else
    {
    bprint( 27 );
    bprint( 'F' );
    }

if( dialog[ITALIC].ob_state & SELECTED )/* set/clear italic                 */
    {
    bprint( 27 );
    bprint( 52 );
    }
else
    {
    bprint( 27 );
    bprint( 53 );
    }

if( dialog[WIDE].ob_state & SELECTED )  /* set/clear wide                   */
    {
    bprint( 27 );
    bprint( 14 );
    }
else
    bprint( 20 );

if( dialog[COND].ob_state & SELECTED )  /* set/clear condensed              */
    {
    bprint( 27 );
    bprint( 15 );
    }
else
    bprint( 18 );

if( dialog[PERF].ob_state & SELECTED )  /* set/clear skipover               */
    {
    bprint( 27 );
    bprint( 78 );
    bprint( 6 );
    }
else
    {
    bprint( 27 );
    bprint( 79 );
    }

bprint( 27 );                           /* set/clear quiet                  */
bprint( 115 );
bprint( ( dialog[QUIET].ob_state & SELECTED ) );

bprint( 27 );                           /* set/clear unidirectional         */
bprint( 85 );
bprint( ( dialog[UNIDIR].ob_state & SELECTED ) );
}

bprint( value )                         /* Using this procedure instead of  */
char value;                             /* hundreds of Bconout( 0, n )'s    */
{                                       /* saves about 500 bytes of code!   */
int x, y, w, h, button;

if( (Cprnos() != 0) && (error == FALSE) )
        Cprnout( value );
else if ( error == FALSE )              /* Display warning message          */
        {
        button = form_alert( 2, "[3][ | |Printer is not responding][Abandon| OK ]" );
        error = button == 1;
        }                               /* Erase warning box by redrawing   */
}                                       /* that area of dialog box          */


load_info()                             /* Deal with 'sys' file             */
{
if( !Fsfirst( sys_file, 0 ) )           /* If the file exists               */
    {
    stream = fopen( sys_file, "r" );    /* open a stream to it              */
    fread( &current, 7, 1, stream );    /* and read the info                */
    fclose( stream );
    }
}

save_info()                             /* Save the current information     */
{
stream = fopen( sys_file, "w" );
if( stream != 0l )
    {
    if( fwrite( &current, 7, 1, stream ) != 1 )
        Cconws("SYS file not written correctly" );
    fclose( stream );
    }
else
    {
    Cconws( "Cannot open sys file" );
    Cconin();
    }
}
/*  -------------------------------------------------------------
    This is a standard unit that I use whenever the file selector
    is needed in a program.
    -------------------------------------------------------------*/

/* Supply pointer to enough storage to hold the path and name
   chosen, returns TRUE if OK clicked or FALSE if CANCEL
   Needs STRINGS.H library   */

select( filespec )                    /* This routine takes care of all of  */
char *filespec;                       /* the niceties of using the file     */
{                                     /* selector                           */
static char path[160];
static char name[15];
int button, count;
static int first = TRUE;

if( first )                           /* been here before?                  */
    {
    first = FALSE;                    /* if this is the first time through  */
    name[0] = 0;                      /* clear the text in "name"           */
    strcpy( path, " :\\*.*" );
    path[0] = Dgetdrv() + 'A';
    }
else
    strcat( path, "*.*" );            /* Otherwise set up the wildcards     */

fsel_input( path, name, &button );    /* choose file                        */

count = strlen( path );               /* get rid of the wildcards           */
while( path[count] != '\\' )
    count--;
path[count+1] = 0;

if( button == 1 )                     /* If OK is clicked recreate the full */
    {                                 /* path/filename                      */
    strcpy( filespec, path );
    strcat( filespec, name );
    }            
return button;                        /* Return the button that was clicked */
}

print_file()                          /* Print a file                       */
{
FILE *stream;
char the_file[160];
char byte;

if( select( the_file ) )              /* Was a filename selected?           */
    {
    draw( DIALOG, MAX_DEPTH );        /* Erase the file selector            */
    stream = fopen( the_file, "r" );  /* Try to open stream to the file     */
    if( stream != 0l )                /* Opened OK                          */
        {
        graf_mouse( HOURGLASS, 0l );  /* Say the program is 'busy'          */
        while( !feof(stream)&!Cconis() )
            {                         /* Read bytes from the file and print */
            fread( &byte, 1, 1, stream );
            bprint( byte );
            }
        bprint( 12 );                /* Do a form feed at the end           */
        graf_mouse( ARROW, 0l );     /* Finished being 'busy'               */
        fclose( stream );
        deselect(PRINT);
        draw( PRINT, 0 );            /* Reset the button on the dialog      */
        }
    else                             /* Couldn't open the file              */
        {
        form_alert( 1, "[3][ |Cannot open the file][- OK -]" );
        deselect(PRINT);
        draw( PRINT, 0 );
        }
    }
else                                 /* File wasn't selected                */
    {
    deselect(PRINT);
    draw( DIALOG, MAX_DEPTH );
    }
}

deselect( an_object )                /* These routines are used to reduce   */
int an_object;                       /* the size of the code                */
{
dialog[an_object].ob_state &= ~SELECTED;
}

draw( an_object, depth )
{
objc_draw( dialog, an_object, depth, x, y, w, h );
}

dialog_print( dial_obj, value )
int dial_obj;
char value;
{
dialog[dial_obj].ob_spec[0] = (value/10)+'0';
dialog[dial_obj].ob_spec[1] = (value%10)+'0';
}
