/****************************************************************************/
/* UW_TUT9.C                                                                */
/*                                                                          */
/* NOTE: THIS FILE IS PUBLIC DOMAIN AND MAY BE MODIFIED AND USED AT WILL    */
/*                                                                          */
/* In this tutorial we show how easy it is to run in graphics mode, instead */
/* of the 80x25 text mode we have been using.                               */
/*                                                                          */
/*                                                         Dr. Boyd Gafford */
/*                                                         Kevin Huck       */
/*                                                         EnQue Software   */
/*                                                         09/16/92         */
/****************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#ifndef __TURBOC__
#include <sys\types.h>
#endif
#include <sys\stat.h>
#include <time.h>
#include <ctype.h>
#include <bios.h>
#ifdef __ZTC__
  #include <fg.h>                         /* include Zortech graphics       */
#else
#ifdef M_I86
  #include <graph.h>                      /* include Microsoft graphics     */
#endif
#endif
#ifdef __TURBOC__
  #include <graphics.h>                   /* include Borland graphics       */
#endif
#include "uw.h"                           /* include the necessary headers  */


#define MAX_CUST 50

typedef struct cust
{
  int status;
  int cust_no;
  char business[34];
  char name[34];
  char addr[34];
  char city[34];
  char state[4];
  char zip[10];
  char phone[16];
  char fax[16];
  char date[10];
  char memo[34];
  char unused[26];                                /* round out to 256 bytes */
} CUST;

/*------------------------ global window variables -------------------------*/
WINDOW  Desk_wn, Window1;
CUST    Customers[MAX_CUST];
char    Fname[33];

MENU    Top_menu, *Top_mnp = &Top_menu;
MENU    Files_menu, Edit_menu, Print_menu;
MENU    *Drop_mnps[3];

PRINT   Print;

/*-------------------------------- prototypes ------------------------------*/
void init_g(void);
void end_g(void);
int disp_time(void);
void disp_cust(CUST *cp, WINDOW *wnp);
int file_load(CUST *customers);
int file_save(CUST *customers);
int get_fname(char *fname);
void print_cust(CUST *cp, PRINT *p);

/*********/
/* ~main */
/*       ********************************************************************/
/*  Demonstrate data entry capability...                                    */
/****************************************************************************/
int main()
{
  int i, ret_val, cust = 0, end_flag = 0, print_stat = 0;
  WINDOW *wnp;
  CUST *cp;
  uchar back_att  = (LIGHTGRAY << 4) | BLACK,
        bdr_att   = (LIGHTGRAY << 4) | BLACK,
        csr_att   = (CYAN << 4) | YELLOW,
        first_att = (LIGHTGRAY << 4) | RED;
  
  wnp = &Window1;                         /* set local window pointer       */
#ifdef __ZTC__
  force_video(16, 80, 25);                /* force Zortech to EGA mode      */
#else
  init_video(80, 25);                     /* init video for 80 x 25 screen  */
#endif
  init_clock(0x3333);                     /* init clock irq at 91 tics/sec  */
  init_mouse();                           /* init mouse if available        */
  
  init_uw_graphics(640, 350, 14, 14, -1, -1);
  init_g();
  
  wn_create(0, 0, V_cols-1, V_rows-1, NO_BDR, WN_NORMAL, &Desk_wn);
  link_window(&Desk_wn);

  /*------------------------ create the menu system ------------------------*/
  Drop_mnps[0] = &Files_menu;
  Drop_mnps[1] = &Edit_menu;
  Drop_mnps[2] = &Print_menu;

  menu_create(0, 0, V_cols - 1, 0, M_HORIZONTAL,
              back_att, bdr_att, csr_att, first_att,
              NO_BDR, WN_NORMAL, Top_mnp);
  item_add( "   Files   ", 1, 3, &Top_menu );
  item_add( "   Edit    ", 2, 3, &Top_menu );
  item_add( "   Print   ", 8, 3, &Top_menu );

  menu_create(0, 1, 14, 5, M_VERTICAL,
    back_att, bdr_att, csr_att, first_att,
    SGL_BDR, WN_NORMAL, Drop_mnps[0]);
  item_add( " Load File", 4, 1, &Files_menu );
  item_add( " Save File", 5, 1, &Files_menu );
  item_add( "   Quit   ", 3, 3, &Files_menu );

  menu_create(11, 1, 32, 4, M_VERTICAL,
    back_att, bdr_att, csr_att, first_att,
    SGL_BDR, WN_NORMAL, Drop_mnps[1]);
  item_add( " Clear Current", 6, 7, &Edit_menu );
  item_add( " Clear All    ", 7, 7, &Edit_menu );

  menu_create(22, 1, 43, 4, M_VERTICAL,
    back_att, bdr_att, csr_att, first_att,
    SGL_BDR, WN_NORMAL, Drop_mnps[2]);
  item_add( " Print Current", 9, 7, &Print_menu );
  item_add( " Print All    ", 10, 7, &Print_menu );

  set_idle_func(disp_time);               /* set background clock function  */

  wn_create(5, 5, 75, 20, SLD_BDR, WN_POPUP, wnp);
  wn_color(YELLOW, BLUE, wnp);            /* change the window colors       */
  wn_bdr_color(WHITE, BLUE, wnp);         /* change the border's colors     */
  link_window(wnp);

  /*------------- initialize first customer as EnQue Software --------------*/
  cp = &Customers[0];
  strcpy(cp->business, "EnQue Software"); 
  strcpy(cp->name, "Kevin Huck & Boyd Gafford");  
  strcpy(cp->addr, "Rt. 1 Box 116C"); 
  strcpy(cp->city, "Pleasant Hill");  
  strcpy(cp->state, "MO");  
  strcpy(cp->zip, "64080"); 
  strcpy(cp->phone, "(816)987-2515"); 
  strcpy(cp->fax, "(816)987-2515");      
  strcpy(cp->date, "09/11/92");      
  strcpy(cp->memo, "BBS 816-358-8990"); 

  /*------------------------ initialize the printer ------------------------*/
  if( init_printer("LPT1", NULL, 2048L, 2048L, &Print) )
    print_stat = 1;

  Top_mnp->csr_pos = M_MAX_ENTRIES;    /* set to prevent menu from hiliting */
  menu_set(Top_mnp);          /* on entry, since menu is not active until   */
  Top_mnp->csr_pos = 0;       /* Alt-F, Alt-E, or Alt-P is hit              */

  wn_color(LIGHTGRAY, RED, &Desk_wn);
  wn_plst(CENTERED, 3, "Use cursor keypad to select customer", &Desk_wn);
  wn_plst(CENTERED, 4, "or click on cursor buttons at bottom of screen", &Desk_wn);
  wn_plst(CENTERED, 22, "<Up> <Dn>  <PgUp> <PgDn>  <Home> <End>", &Desk_wn);
  wn_color(YELLOW, RED, &Desk_wn);
  while(!end_flag)
  {
    cp = &Customers[cust];
    mv_cs(1,1, wnp);
    wn_printf(wnp, "Customer:%3d", cust+1);
    disp_cust(cp, wnp);
    m_show();
    wait_event();
    m_hide();
    if( Event.is_mouse )                            /* process mouse action */
    {
      if( range(0,Event.m_x,11) && (Event.m_y == 0) )
        Event.key = KEY_ALT_F;
      else if( range(11,Event.m_x,22) && (Event.m_y == 0) )
        Event.key = KEY_ALT_E;
      else if( range(22,Event.m_x,33) && (Event.m_y == 0) )
        Event.key = KEY_ALT_P;

      else if( range( 7,Event.m_x,47) && (Event.m_y == 9) )
        Event.key = 'B';
      else if( range( 7,Event.m_x,47) && (Event.m_y == 10) )
        Event.key = 'N';
      else if( range( 7,Event.m_x,47) && (Event.m_y == 11) )
        Event.key = 'A';
      else if( range( 7,Event.m_x,47) && (Event.m_y == 12) )
        Event.key = 'C';
      else if( range(50,Event.m_x,59) && (Event.m_y == 12) )
        Event.key = 'S';
      else if( range(61,Event.m_x,71) && (Event.m_y == 12) )
        Event.key = 'Z';
      else if( range( 7,Event.m_x,47) && (Event.m_y == 13) )
        Event.key = 'P';
      else if( range( 7,Event.m_x,47) && (Event.m_y == 14) )
        Event.key = 'F';
      else if( range( 7,Event.m_x,47) && (Event.m_y == 15) )
        Event.key = 'D';
      else if( range( 7,Event.m_x,47) && (Event.m_y == 16) )
        Event.key = 'M';

      else if( range( 21,Event.m_x,24) && (Event.m_y == 22) )
        Event.key = KEY_UP;
      else if( range( 26,Event.m_x,29) && (Event.m_y == 22) )
        Event.key = KEY_DN;
      else if( range( 32,Event.m_x,37) && (Event.m_y == 22) )
        Event.key = KEY_PGUP;
      else if( range( 39,Event.m_x,44) && (Event.m_y == 22) )
        Event.key = KEY_PGDN;
      else if( range( 47,Event.m_x,52) && (Event.m_y == 22) )
        Event.key = KEY_HOME;
      else if( range( 54,Event.m_x,58) && (Event.m_y == 22) )
        Event.key = KEY_END;
      else
        Event.key = 0;  
    }
    switch(Event.key)
    {
      /*-------------------------- process menus ---------------------------*/
      case KEY_ALT_Q:                                       /* quit program */
        end_flag = 1;
        break;
      case KEY_ALT_F: case KEY_ALT_E: case KEY_ALT_P:
        m_show();
        if( Event.key == KEY_ALT_F )
          ret_val = menu_system_ll(&Top_menu,&Drop_mnps[0],0,'F',M_EXIT_ON_ESC);
        else if( Event.key == KEY_ALT_E )
          ret_val = menu_system_ll(&Top_menu,&Drop_mnps[0],0,'E',M_EXIT_ON_ESC);
        else
          ret_val = menu_system_ll(&Top_menu,&Drop_mnps[0],0,'P',M_EXIT_ON_ESC);
        switch( ret_val )
        {
          case 3:                                           /* quit program */
            end_flag = 1;
            break;
          case 4:                                           /* load file    */
            file_load(Customers);
            break;
          case 5:                                           /* save file    */
            file_save(Customers);
            break;
          case 6:                                           /* clear one    */
            setmem(cp, sizeof(CUST), 0);
            break;
          case 7:                                           /* clear all    */
            setmem(Customers, sizeof(Customers), 0);
            break;
          case 9:                                           /* print one    */
            if( print_stat )
              print_cust(cp, &Print);
            break;
          case 10:                                          /* print all    */
            if( print_stat )
              for( i = 0; i < MAX_CUST; i++ )
                if( strlen(Customers[i].name) )             /* not empty?   */
                  print_cust(&Customers[i], &Print);
            break;
        }
        break;
      /*----------------------- process cursor keys ------------------------*/
      case KEY_HOME:
        cust = 0;
        break; 
      case KEY_END:
        cust = MAX_CUST-1;
        break; 
      case KEY_DN: 
        if( cust < MAX_CUST-1 )
          cust++;
        break;
      case KEY_UP: 
        if( cust > 0 )
          cust--;
        break;
      case KEY_PGUP: 
        if( cust >= 10 )
          cust -= 10;
        else
          cust = 0;
        break;
      case KEY_PGDN: 
        if( cust < MAX_CUST-11 )
          cust += 10;
        else
          cust = MAX_CUST-1;
        break;
      /*-------------------- process field edit keys -----------------------*/
      case 'b': case 'B':                         /* get new business name  */
        mv_cs( 11, 3, wnp);
        wn_gets_ll(cp->business, "________________________________",
                                 "********************************",
          swap_nibbles(wnp->att), G_UP_FST_CHAR2 | G_STRIP_END, 32, wnp);
        break;
      case 'n': case 'N':                         /* get new contact name   */
        mv_cs( 11, 4, wnp);
        wn_gets_ll(cp->name, "________________________________",
                             "********************************",
          swap_nibbles(wnp->att), G_UP_FST_CHAR2 | G_STRIP_END, 32, wnp);
        break;
      case 'a': case 'A':                         /* get new address        */
        mv_cs( 11, 5, wnp);
        wn_gets_ll(cp->addr, "________________________________",
                             "********************************",
          swap_nibbles(wnp->att), G_UP_FST_CHAR2 | G_STRIP_END, 32, wnp);
        break;
      case 'c': case 'C':                         /* get new city           */
        mv_cs( 11, 6, wnp);
        wn_gets_ll(cp->city, "________________________________",
                             "********************************",
          swap_nibbles(wnp->att), G_UP_FST_CHAR2 | G_STRIP_END, 32, wnp);
        break;
      case 's': case 'S':                         /* get new state          */
        mv_cs( 51, 6, wnp);
        wn_gets_ll(cp->state, "__", "UU",
          swap_nibbles(wnp->att), G_EXIT_ON_FILL|G_STRIP_END, 2, wnp);
        break;
      case 'z': case 'Z':                         /* get new zip            */
        mv_cs( 60, 6, wnp);
        wn_gets_ll(cp->zip, "_____", "#####",
          swap_nibbles(wnp->att), G_EXIT_ON_FILL|G_STRIP_END, 5, wnp);
        break;
      case 'p': case 'P':                         /* get new phone number   */
        mv_cs( 11, 7, wnp);
        wn_gets_ll(cp->phone, "(___)___-____", " ### ### ####",
          swap_nibbles(wnp->att), G_EXIT_ON_FILL, 14, wnp);
        break;                    
      case 'f': case 'F':                         /* get new fax number     */
        mv_cs( 11, 8, wnp);
        wn_gets_ll(cp->fax, "(___)___-____", " ### ### ####",
          swap_nibbles(wnp->att), G_EXIT_ON_FILL, 14, wnp);
        break;
      case 'd': case 'D':                         /* get new date           */
        mv_cs( 11, 9, wnp);
        wn_gets_ll(cp->date, "__/__/__", "## ## ##", swap_nibbles(wnp->att),
          G_EXIT_ON_FILL, 8, wnp);
        break;
      case 'm': case 'M':                         /* get new memo field     */
        mv_cs( 11, 10, wnp);
        wn_gets_ll(cp->memo, "________________________________",
                             "********************************",
          swap_nibbles(wnp->att), G_STRIP_END, 32, wnp);
        break;

    }
  }

  unlink_window(wnp);                     /* remove the window from screen  */
  wn_destroy(wnp);
  set_idle_func(NULL);                    /* remove background function     */
  unlink_window(&Desk_wn);                /* remove the window from screen  */
  wn_destroy(&Desk_wn);
  end_clock();
  end_video();                            /* clean up before we exit        */
  end_printer(&Print);
  end_mouse();
  end_g();
  return(1);
}
/*** end of main ***/

/**************/
/* ~disp_time */
/*            ***************************************************************/
/*  This routine is called in the background by wait_event and will display */
/*  the time once per second.  Notice the use of the global variables       */
/*  Uw_timers.  There is an array of four "countdown" timers that are user  */
/*  accessible.  Each "timer tic" will decrement the counts by one, until   */
/*  0 is reached.  By "reloading" the timer with "Tics_per_sec", we only    */
/*  display the time of day once per second.  "Tics_per_sec" is set         */
/*  by init_clock.                                                          */
/****************************************************************************/
int disp_time(void)
{
  time_t t;
  print_in_bkgrnd();                            /* call this to print       */
  if( !Uw_timers[0] )                           /* has one second passed?   */
  {
    Uw_timers[0] = Tics_per_sec;                /* if so, reload timer      */
    t = time(NULL);                             /* get time                 */
    mv_cs(55, V_rows-1, &Desk_wn);              /* move window cursor       */
    wn_st_qty(ctime(&t), 24, &Desk_wn);         /* output 24 characters     */
    return(1);
  }
  return(0);
}
/*** end of disp_time ***/

/**************/
/* ~disp_cust */
/*            ***************************************************************/
/*  This routine displays a customer in the desired window...               */
/****************************************************************************/
void disp_cust(CUST *cp, WINDOW *wnp)
{
  int r = 3;

  mv_cs( 1, r++, wnp );
  wn_printf( wnp, "Business: %-32s", cp->business);
  mv_cs( 1, r++, wnp );
  wn_printf( wnp, "Name    : %-32s", cp->name );
  mv_cs( 1, r++, wnp );
  wn_printf( wnp, "Address : %-32s", cp->addr );
  mv_cs( 1, r++, wnp );
  wn_printf( wnp, "City    : %-32s State: %2s  Zip: %5s",
    cp->city, cp->state, cp->zip );
  wn_cleol(wnp);                                    /* clear to end of line */
  mv_cs( 1, r++, wnp );
  wn_printf( wnp, "Phone   : %-16s", cp->phone );
  mv_cs( 1, r++, wnp );
  wn_printf( wnp, "Fax     : %-16s", cp->fax );
  mv_cs( 1, r++, wnp );
  wn_printf( wnp, "Date    : %-10s", cp->date );
  mv_cs( 1, r++, wnp );
  wn_printf( wnp, "Memo    : %-32s", cp->memo );
}
/*** end of disp_cust ***/

/**************/
/* ~file_load */
/*            ***************************************************************/
/*  This routine loads a file from disk into the customer array...          */
/****************************************************************************/
int file_load(CUST *customers)
{
  FILE *fp;
  
  if( get_fname(Fname) )
  {
    if( (fp = fopen(Fname, "rb")) != NULL )
    {
      fread(customers, sizeof(CUST), MAX_CUST, fp);
      fclose(fp);
      tone(1024,10);
      return(1);
    }
  }
  return(0);
}
/*** end of file_load ***/

/**************/
/* ~file_save */
/*            ***************************************************************/
/*  This routine saves a file to disk from the customer array...            */
/****************************************************************************/
int file_save(CUST *customers)
{
  FILE *fp;
  
  if( get_fname(Fname) )
  {
    if( (fp = fopen(Fname, "wb")) != NULL )
    {
      fwrite(customers, sizeof(CUST), MAX_CUST, fp);
      fclose(fp);
      tone(1024,10);
      return(1);
    }
  }
  return(0);
}
/*** end of file_load ***/

/**************/
/* ~get_fname */
/*            ***************************************************************/
/*  This routine prompts the user for a filename using a popup window...    */
/****************************************************************************/
int get_fname(char *fname)
{
  int ret_val = 1;
  WINDOW wn;
  
  wn_create(20, 8, 60, 10, SLD_BDR, WN_POPUP, &wn);
  wn_set(&wn);
  wn_plst(4, 0, "Enter filename:", &wn);
  if( wn_gets_ll(fname, "____________", "************",
      swap_nibbles(wn.att), G_STRIP_END, 12, &wn) == KEY_ESC )
    ret_val = 0;
  wn_destroy(&wn);
  return(ret_val);
}
/*** end of get_fname ***/

/***************/
/* ~print_cust */
/*             **************************************************************/
/*  This routine prints a customer in the desired window...                 */
/****************************************************************************/
void print_cust(CUST *cp, PRINT *p)
{
  print_printf( p, "Business: %-32s\r\n", cp->business);
  print_printf( p, "Name    : %-32s\r\n", cp->name );
  print_printf( p, "Address : %-32s\r\n", cp->addr );
  print_printf( p, "City    : %-32s State: %2s  Zip: %5s\r\n",
    cp->city, cp->state, cp->zip );
  print_printf( p, "Phone   : %-16s\r\n", cp->phone );
  print_printf( p, "Fax     : %-16s\r\n", cp->fax );
  print_printf( p, "Date    : %-10s\r\n", cp->date );
  print_printf( p, "Memo    : %-32s\r\n", cp->memo );
  print_char(12,p);                                     /* print form feed  */
}
/*** end of print_cust ***/

/***********/
/* ~init_g */
/*         ******************************************************************/
/*  simple generic init graphics routine...                                 */
/****************************************************************************/
void init_g(void)
{
#ifdef __TURBOC__
  int    g_driver;                          /* the graphics device driver   */
  int    g_mode;                            /* the graphics mode value      */
  int    err_code;                          /* reports any graphics errors  */

  registerbgidriver(EGAVGA_driver);
  g_driver = EGA;                           /* request EGA 640x350          */
  g_mode = EGAHI;
  initgraph( &g_driver, &g_mode, "" );
  err_code = graphresult();                 /* read result of init          */
  if( err_code != grOk )
  {                                         /* error during init            */
    printf("Graphics System Error: %s\n", grapherrormsg(err_code));
    exit( 1 );
  }
#endif
#ifdef __ZTC__
#else
#ifdef M_I86
  _setvideomode(_ERESCOLOR);
#endif
#endif
}
/*** end of init_g ***/

/**********/
/* ~end_g */
/*        *******************************************************************/
/*  simple generic end graphics routine...                                  */
/****************************************************************************/
void end_g(void)
{
#ifdef __TURBOC__
  closegraph();
#endif
#ifdef __ZTC__
#else
#ifdef M_I86
  _setvideomode(_DEFAULTMODE);
#endif
#endif
}
/*** end of end_g ***/

/*** END OF FILE ***/
