
/* ---------------------------------------------------------------
   HELP POP-UP for SunView Applications
   
   This package automatically handles help screens within a
   SunView application.  When help is invoked, a window pops up
   listing documentation stored in some file.  The user is
   allowed to page forward or back through the documentation,
   or quit.

   INSTALL IN AN APPLICATION AS FOLLOWS:

   Near the beginning of a program, insert an include statement:

        #include "help.c"

   After creating the base frame, create the help frame as:

        create_help_popup(base_frame);

   For each application, call

        add_help_button(panel_item, help_file_name);

   The notify procedure for each help button must be "help_proc"
 --------------------------------------------------------------- */

#define help_lines        22
#define help_cols         60
#define help_buff        255
#define max_help_buttons  10
#define new_page_char    ''

#include <pixrect/pixrect_hs.h>

Window      help_frame, help_panel;
Panel_item  bitmap_item, help_msg[help_lines];
Panel_item  help_fwd_item, help_back_item;

static void help_page_back(), help_page_fwd(), quit_help();

static short  help_fwd_array[] = {
#include "pagefwd.icon"
};
mpr_static(help_fwd_icon, 64, 64, 1, help_fwd_array);

static short  help_back_array[] = {
#include "pageback.icon"
};
mpr_static(help_back_icon, 64, 64, 1, help_back_array);


int         help_at_eof, help_page, help_buttons;
char        help_files[max_help_buttons][help_buff];
char        curr_help_file[help_buff];
Panel_item  help_button_items[max_help_buttons];
Pixrect     *bitmap_image;


/* ---------------------------------------------------------------
   CREATE_HELP_POPUP (base_frame)
   
   This subroutine creates the SunView frame and panel items
   necessary for the help function.  Also, variables keeping
   track of help buttons and their associated documentation
   are initialized.

   INPUTS:  base_frame ... Frame variable of calling application

   OUTPUTS:            ... none
 --------------------------------------------------------------- */

create_help_popup(base_frame)
Window  base_frame;
{
    int i;

    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       Set up help frame with "page forward," "page back," "quit"
       and help message lines.
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    help_frame = window_create(base_frame, FRAME, FRAME_SHOW_LABEL, FALSE, 0);

    if (help_frame == NULL)
    {  fprintf(stderr,"Sunview error:  too many open windows.\n");
       exit(1);
    }

    help_panel = window_create(help_frame, PANEL, WIN_COLUMNS, help_cols, 0);

    if (help_panel == NULL)
    {  fprintf(stderr,"Sunview error:  too many open windows.\n");
       exit(1);
    }

    help_back_item = panel_create_item(help_panel, PANEL_MESSAGE,
                   PANEL_LABEL_IMAGE, &help_back_icon,
                   PANEL_NOTIFY_PROC, help_page_back,
                   0);

    help_fwd_item = panel_create_item(help_panel, PANEL_MESSAGE,
                   PANEL_LABEL_IMAGE, &help_fwd_icon,
                   PANEL_NOTIFY_PROC, help_page_fwd,
                   0);

    panel_create_item(help_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE,
                   panel_button_image(help_panel, "Quit", 5, 0),
                   PANEL_ITEM_X, ATTR_COL(help_cols-10),
                   PANEL_NOTIFY_PROC, quit_help,
                   0);

    bitmap_item = panel_create_item(help_panel, PANEL_MESSAGE,
                   PANEL_ITEM_X, 4, PANEL_ITEM_Y, 70,
                   PANEL_SHOW_ITEM, FALSE, 0);

    for(i=0; i < help_lines; i++)
       help_msg[i] = panel_create_item(help_panel, PANEL_MESSAGE,
                       PANEL_ITEM_X, 4, PANEL_ITEM_Y, i*17+70, 0);
 
    window_set(help_panel, WIN_FIT_HEIGHT, 15, 0);
    window_fit(help_frame);

    help_at_eof  = FALSE;
    help_page    = 0;
    help_buttons = 0;
    bitmap_image = NULL;
}


/* ---------------------------------------------------------------
   ADD_HELP_BUTTON (help_item, help_file_name)
   
   This subroutine adds a help button definition to the list
   of known buttons.  This way, when "help_proc" is invoked,
   the selected item determines which help file will be
   displayed.

   INPUTS:       help_item ... panel item for help function
            help_file_name ... character string of file name
                                 with documentation

   OUTPUTS:            ... arrays "help_button_items" and
                             "help_files" are updated, as well
                             as the counter "help_buttons"
 --------------------------------------------------------------- */

add_help_button (help_item, help_file_name)
Panel_item  help_item;
char        *help_file_name;
{
    if (help_buttons < max_help_buttons)
    {  ++help_buttons;
       help_button_items[help_buttons-1] = help_item;
       strcpy(help_files[help_buttons-1],help_file_name);
    }
}


/* ---------------------------------------------------------------
   HELP_PROC (help_item)
   
   When a help button is selected, the help_proc is invoked,
   passing the item which was selected.  This item is compared
   against a list of known items, and if it is found, the
   help window is made visible.  The documentation associated
   with the item via the "help_files" array is then displayed.
   If the item is not found on the list, then the help is aborted.

   INPUTS:       help_item ... panel item calling the help function

   OUTPUTS:            ... the help window is made visible
 --------------------------------------------------------------- */

help_proc (help_item)
Panel_item  help_item;
{
    int i, j;

    j = help_buttons;                       /* find calling button */
    for (i=0; i < help_buttons; i++)
       if (help_button_items[i] == help_item)
          j = i;

    if (j != help_buttons)                  /* if button is known... */
    {  window_set(help_frame, WIN_SHOW, TRUE, 0);

       help_at_eof = FALSE;
       help_page   = 0;
       strcpy(curr_help_file,help_files[j]);

       show_help_page(help_page);
       panel_set(help_back_item, PANEL_SHOW_ITEM, FALSE, 0);
       if (help_at_eof)
          panel_set(help_fwd_item, PANEL_SHOW_ITEM, FALSE, 0);
       else
          panel_set(help_fwd_item, PANEL_SHOW_ITEM, TRUE, 0);
    }
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   HELP_PAGE_FWD()
   Advances the displayed documentation by one page.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

static void help_page_fwd()
{
    if (!help_at_eof)
    {  ++help_page;
       show_help_page(help_page);

       panel_set(help_back_item, PANEL_SHOW_ITEM, TRUE, 0);
       if (help_at_eof)
          panel_set(help_fwd_item, PANEL_SHOW_ITEM, FALSE, 0);
    }
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   HELP_PAGE_BACK()
   Moves backward one page in the documentation.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

static void help_page_back()
{
    if (help_page > 0)
    {  help_at_eof = FALSE;
       --help_page;
       show_help_page(help_page);

       panel_set(help_fwd_item, PANEL_SHOW_ITEM, TRUE, 0);
       if (help_page == 0)
          panel_set(help_back_item, PANEL_SHOW_ITEM, FALSE, 0);
    }
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   SHOW_HELP_PAGE()
   Displays the current page of documentation in the file
   "curr_help_file."  If name of current help file ends with
   ".bitmaps" then file is a list of bitmap file names.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

show_help_page(help_page)
int help_page;
{
    int   i, j, end_page, quit;
    char  line[help_cols], root[help_buff], ext[help_buff], *p;
    FILE  *fp, *fopen();

    if (*curr_help_file != '\0' && *curr_help_file != ' ')
    {  if ((fp = fopen(curr_help_file,"r")) == NULL)
       {  for (j=0; j < help_lines; j++)
             panel_set(help_msg[j], PANEL_LABEL_STRING, "", 0);
          panel_set(help_msg[0], PANEL_LABEL_STRING,
                    "Documentation file unreachable.", 0);
          help_at_eof = TRUE;
       }

       else
       {  get_extension(curr_help_file,root,ext);

          /* If current help file is a list of bitmap file names,
             then show bitmaps                                    */

          if (strcmp(ext,".bitmaps") == 0)
          {  for (i=0, quit=FALSE; i <= help_page && !quit; i++)
             {  quit |= (fgets(root,help_buff,fp) == NULL);
                for (p=root; *p != '\0'; p++)
                   if (*p == '\n')  *p = '\0';
             }

             if (quit)
                help_at_eof = TRUE;

             else
             {  for (j=0; j < help_lines; j++)
                   panel_set(help_msg[j], PANEL_LABEL_STRING, "", 0);
                load_bitmap(root, bitmap_item);

                help_at_eof = (fgets(root,help_buff,fp) == NULL);
             }
          }


          /* Otherwise, list contents of the help file   */

          else
          {  panel_set(bitmap_item, PANEL_SHOW_ITEM, FALSE, 0);

             for (i=0, quit=FALSE; i < help_page && !quit; i++)

                for (j=0, end_page=FALSE;
                     j < help_lines && !end_page && !quit; j++)

                {  quit |= (fgets(line,help_cols,fp) == NULL);
                   if (*line == new_page_char)
                      end_page = TRUE;
                }


             for (j=0, end_page=FALSE;
                  j < help_lines && !end_page && !quit; j++)

             {  quit |= (fgets(line,help_cols,fp) == NULL);
                if ((*line == new_page_char) || quit)
                {  end_page = TRUE;
                   panel_set(help_msg[j], PANEL_LABEL_STRING, "", 0);
                }
                else if (!quit)
                   panel_set(help_msg[j], PANEL_LABEL_STRING, line, 0);
             }

             help_at_eof = quit;

             if (end_page || quit)
                for (; j < help_lines; j++)
                   panel_set(help_msg[j], PANEL_LABEL_STRING, "", 0);

             window_set(help_panel, WIN_COLUMNS, help_cols,
                          WIN_FIT_HEIGHT, 15, 0);
             window_fit(help_frame);
          }
       }
       fclose(fp);
    }
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   LOAD_BITMAP()
   Reads in a pixrect image and displays it.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 
load_bitmap(filename, item)
char        *filename;
Panel_item  item;
{
   FILE     *fp;
 
   if ((fp = fopen(filename,"r")) == NULL)
      panel_set(item, PANEL_SHOW_ITEM, FALSE, 0);

   else
   {  if (bitmap_image != NULL)
         pr_destroy(bitmap_image);

      if ((bitmap_image = pr_load(fp, NULL)) == NULL)
         panel_set(item, PANEL_SHOW_ITEM, FALSE, 0);

      else
      {  panel_set(item, PANEL_LABEL_IMAGE, bitmap_image,
                   PANEL_SHOW_ITEM, TRUE, 0);
         window_set(help_panel, WIN_FIT_HEIGHT, 10, WIN_FIT_WIDTH, 10, 0);
         window_fit(help_frame);
      }
   }

   fclose(fp);
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   QUIT_HELP()
   Makes the help frame invisible, thereby terminating help.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

static void quit_help()
{
    window_set(help_frame, WIN_SHOW, FALSE, 0);
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   GET_EXTENSION (filename, root, ext)
     Splits a file name into its root name and extension.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
get_extension(filename, root, ext)
char *filename, *root, *ext;
{
   char *p, *q;

   p = filename + strlen(filename);
   for (p=filename; *p != '.' && *p != '\0'; p++)
      ;

   for (q=filename; q != p; q++)
      *root++ = *q;

   *root = '\0';

   for (q=p; *q != '\0'; q++)
      *ext++ = *q;

   *ext = '\0';
}
