text: /***************************************************************************/
  /* 																								*/
  /*	MENU.C																						*/
  /* 																								*/
  /*		Copyright (c) 1991 - Microsoft Corp.											*/
  /*		All rights reserved.																	*/
  /*		Microsoft Confidential																*/
  /* 																								*/
  /* DOS 5.00 OEM install highlighted data selection functions					*/
  /* 																								*/
  /* Created 02-21-90 - johnhe																*/
  /***************************************************************************/
  
  #include		<stdio.h>
  #include		<malloc.h>
  
  #include		<alias.h>
  #include		<bios_io.h>
  #include		<window.h>
  #include		<strlib.h>
  
  #include		"global.h"
  
  /***************************************************************************/
  
  extern int	GetChar				( void );
  extern int	GetCharExtension	( void );
  
  /***************************************************************************/
  
  static void InitMenu 		( int WindowTop );
  static void HiLite			( int Option, int fOn );
  static void OptionUp 		( void );
  static void OptionDown		( void );
  static void OptionLeft		( void );
  static void OptionRight 	( void );
  static int 	MyGetSelection	( int Top, int Cols, int DefaultOpt, char **apszList );
  
  /***************************************************************************/
  
  static char			**apszText;					/* Array of menu option strings	*/
  static WINDOW		Win;							/* Menu window structure			*/
  static int			Columns;						/* Number of option columns		*/
  static int			StrsPerCol;					/* Number of strs in each column	*/
  static int			ColWidth;					/* Number of chrs in each column	*/
  static int			TotalStrs;					/* Total number of option strs	*/
  static int			MaxOpt;						/* Max option number based 0		*/
  static int			Current;						/* Current hi-lited option 		*/
  static int			AddShadow = TRUE;			/* Used by MyPromptSelect() to	*/
  														/* signal not a shadow window		*/
  
  /***************************************************************************/
  /* Allows the user to select an option from a menu by using the scroll		*/
  /* bar. Blank entries can be included in the menu in which case the menu	*/
  /* bar will skip over the blank selection.											*/
  /* 																								*/
  /*	int MyGetSelection( int Top, int Cols, int DefaultOpt, char **apszList )*/
  /*																									*/
  /*	ARGUMENTS:	Top		- Row on screen where top of menu window should be	*/
  /*					DefaultOpt- The option number to hi-lite as the default		*/
  /*					apszList	- Ptr to array of strings to display in the menu	*/
  /* RETURNS: 	int	- selected option number, PREVIOUS or ABORT				*/
  /* 																								*/
  /***************************************************************************/
  
  int MyGetSelection( int Top, int Cols, int DefaultOpt, char **apszList )
  {
  	#define			NO_SELECTION	-100		/* Arbitrary non-ascii char value*/
  
  	register			Previous;					/* Last option highlighted			*/
  	register			UserSelection;				/* Menu option selected				*/
  
  	apszText = apszList;							/* in this module can access them*/
  	Columns = Cols;
  	Current = DefaultOpt;
  	InitMenu( Top );
  
  	VideoCursOff();
  	Previous = Current;							/* Don't have a previous HiLite	*/
  	HiLite( Current, ON );						/* HiLite the current option		*/
  
  					/* Keep looping until user presses the <RETURN> key to make	*/
  					/* a selection or <ESC> to abort the selection.					*/
  
  	UserSelection = NO_SELECTION;
  	do
  	{
  		if ( Previous != Current )
  		{														/* HiLite proper selection */
  			HiLite( Previous, OFF );
  			HiLite( Current, ON );
  			Previous = Current;
  		}
  
  		switch( GetChar() )								/* Get input from user	*/
  		{
  
  			case	ESC:											/* <ESC> key pressed		*/
  				UserSelection = PREVIOUS;
  				break;
  
  			case CR:												/* <RETURN> key pressed	*/
  				UserSelection = Current;
  				break;
  
  			case '\0':											/* Was an extended char	*/
  				switch( GetCharExtension() )
  				{
  					case	UP:									/* Move up 1 row			*/
  						OptionUp();
  						break;
  
  					case	DOWN:									/* Move down 1 row		*/
  						OptionDown();
  						break;
  
  					case	LEFT:									/* Move left 1 column	*/
  						OptionLeft();
  						break;
  
  					case	RIGHT:								/* Move right 1 column	*/
  						OptionRight();
  						break;
  
  					default:
  						break;									/* No exted char match	*/
  				}
  				break;
  
  			default:												/* No reg char match 	*/
  				break;
  		}
  	}
  	while( UserSelection == NO_SELECTION  );			/* See if finished		*/
  
  	VideoScrollDn ( Win.Top, Win.Left, Win.Bottom+1, Win.Right+2, 0 , GetBoxColor());
  	
  	return( UserSelection );
  }
  
  /***************************************************************************/
  /* Initializes the menu window structure and displays the menu it on the	*/
  /* screen. This function should only be called by MyGetSelection() because	*/
  /* it relies on static globals which are initialized by MyGetSelection().	*/
  /*																									*/
  /*	static void InitMenu( int WindowTop )												*/
  /*																									*/
  /*	ARGUMENTS:	WindowTop	- Screen row where top of window should be		*/
  /* RETURNS:		void																			*/
  /*																									*/
  /***************************************************************************/
  
  static void InitMenu( int WindowTop )
  {
  	register		Row;												/* Screen row			*/
  	register		Col;												/* Screen col			*/
  	int			i; 												/* Array indice		*/
  	int			TotalWidth; 									/* Total wind width	*/
  
  	ColWidth = (int)MaxStrLen( apszText ) + 2;
  	TotalStrs = GetNumberStrings( apszText );
  	MaxOpt = TotalStrs - 1;
  
  	StrsPerCol = TotalStrs / Columns;
  	TotalWidth = ColWidth * Columns;
  
  #ifdef JAPAN
  	TotalWidth += (TotalWidth & (UCHAR)1) ? (UCHAR)3 : (UCHAR)2;
  #endif
  
  	Win.Top = (char)WindowTop;
  	Win.Bottom = (char)(WindowTop + StrsPerCol + 1);
  	Win.Left = (char)CenterLength( TotalWidth + 2 );
  	Win.Right = Win.Left + (char)TotalWidth + 1;
  
  	Win.Color = Win.BorderColor = (char)GetBoxColor();
  	Win.Type = 1;
  	Win.IsShadow = (char)(AddShadow ? 1 : 0);
  
  	PutWindow( &Win );
  
  	for ( i = 0, Col = Win.Left + 2; Col < Win.Right; Col += ColWidth )
  		for ( Row = WindowTop + 1;	Row < Win.Bottom && i < TotalStrs; Row++ )
  #ifdef JAPAN
  			VideoPutsRowCol( Row, Col+1, apszText[ i++ ] );
  #else
  			VideoPutsRowCol( Row, Col, apszText[ i++ ] );
  #endif
  						/* Need to be sure that default option not a 0 len str	*/
  
  	if ( *(apszText[ Current ]) == EOL )
  	{
  		Current = 0;
  		while( Current < TotalStrs && *(apszText[ Current ]) == EOL )
  			Current++;
  	}
  }
  
  /***************************************************************************/
  /* Function to turn on or off the hi-lite on a specified option in the		*/
  /* menu window. This function should only be called by MyGetSelection()		*/
  /* because it relies on static globals which are initialized by				*/
  /* MyGetSelection().																			*/
  /*																									*/
  /*	static void HiLite( int Option, int fOn )											*/
  /*																									*/
  /*	ARGUMENTS:	Option	- The option to apply the hi-lite to (options are	*/
  /*								  base 0)														*/
  /*					fOn		- If TRUE specifies the function should turn the	*/
  /*								  hi-lite on else turns it off							*/
  /*	RETURNS:		void																			*/
  /*																									*/
  /***************************************************************************/
  
  static void HiLite( int Option, int fOn )
  {
  	register		Row;												/* Screen row			*/
  	register		Col;												/* Screen column		*/
  
  															/* Get pos relative to window	*/
  	if ( Option == 0 )								
  		Row = Col = 0;												/* Divid by 0 check	*/
  	else
  	{
  		Row = Option % StrsPerCol;
  		Col = Option / StrsPerCol;
  	}
  
  	Row += Win.Top + 1;								/* Get pos relative to display*/
  	Col *= ColWidth;
  
  #ifdef JAPAN
  	Col += Win.Left + 2;
  #else
  	Col += Win.Left + 1;
  #endif
  
  	VideoDupAttr( Row, Col,
  					  fOn == ON ? GetBarColor() : GetBoxColor(),
  					  ColWidth );
  }
  
  /***************************************************************************/
  /* These functions handle the movement of the currently selected option.	*/
  /*																									*/
  /* NOTE: These functions call each other and will be come endlessly			*/
  /*			recursive if all option strings are  0 lenght or if the current	*/
  /*			option is on a row where all the options in the row are 0 lenght.	*/
  /*			The only way this will happen is if the call of MyGetSelection()	*/
  /*			specifies a row such as this, and a check is done for this			*/
  /*			condition in InitMenu() and the default is changed to avoid the	*/
  /*			problem. So there will only be a problem if all options are 0		*/
  /*			length strings.																	*/
  /*																									*/
  /*	void OptionUp( void )																	*/
  /*	void OptionDown( void )																	*/
  /*	void OptionLeft( void )																	*/
  /*	void OptionRight( void )																*/
  /*																									*/
  /*	ARGUMENTS:	NONE																			*/
  /*	RETURNS:		void																			*/
  /*																									*/
  /***************************************************************************/
  
  void OptionUp( void )
  {
  	if ( Current > 0 )
  	{
  		do
  			Current--;
  		while( Current > 0 && *(apszText[ Current ]) == EOL );
  	}
  }
  
  void OptionDown( void )
  {
  	if ( Current < MaxOpt )
  	{
  		do
  			Current++;
  		while( Current < MaxOpt && *(apszText[ Current ]) == EOL );
  	}
  }
  
  void OptionLeft( void )
  {
  	register		Tmp;
  
  	Tmp = Current - StrsPerCol;
  	if ( Columns > 1 && Tmp >= 0 )
  		Current = Tmp;
  }
  
  void OptionRight( void )
  {
  	register		Tmp;
  
  	Tmp = Current + StrsPerCol;
  	if ( Columns > 1 && Tmp <= MaxOpt )
  		Current = Tmp;
  }
  
  /***************************************************************************/
  /* Displays a prompt window on the screen which contains text and a			*/
  /* selection box with a variable number of options. The selection box is	*/
  /* within the prompt window with the prompt window centered vertically and	*/
  /* horizonally on the screen.																*/
  /*																									*/
  /*	int MyPromptSelect( char *szStrings[], char *szOpts[], int optdflt )		*/
  /*																									*/
  /*	ARGUMENTS:	szStrings	- Array of ptrs to prompt strings					*/
  /*					szOpts		- Array of ptrs to options for selection box		*/
  /*	RETURNS:		int			- User selection based 0 or PREVIOUS is <ESC>	*/
  /*																									*/
  /***************************************************************************/
  
  int MyPromptSelect( char *szStrings[], char *szOpts[], int optdflt )
  {
  	static char		*szNull = ""; 						/* Zero length string		*/
  	char				*szText[ MAX_STRINGS ];			/* Prompt window strs		*/
  	char				*OldScrn;							/* Buf to hold orig scrn	*/
  	register			i;										/* General purpose			*/
  	unsigned char	OldBoxColor;						/* Orig box color				*/
  	unsigned char	OldBarColor;						/* Orig bar color				*/
  	unsigned long	Cursor;								/* Orig cusor size & pos	*/
  	WINDOW			Window;								/* Prompt window structure	*/
  
  	for ( i = 0; i < MAX_STRINGS; i++ )				/* Build array of ptrs to	*/
  		szText[i] = szNull;								/* zero length strs			*/
  
  	for ( i = 0; szStrings[i] != NULL; i++ )		/* Copy the prompt strings */
  		szText[i] = szStrings[i];
  
  						
  						
  	i++;								/* After this point i + top of prompt window	*/
  	i++;								/* will be top of the selection box				*/
  
  	szText[ GetNumberStrings( szOpts ) + i + 2 ] = NULL;
  
  								/* Determine prompt wind size and allocate a scrn	*/
  								/* buffer, save old scrn and display the prompt		*/
  
  	GetWindowInfo( szText, &Window );
  	OldScrn = GetMemory( (UINT)((Window.Bottom - Window.Top + 2 ) *
  								(Window.Right - Window.Left + 3) * 2 ));
  	Cursor = SaveCursor();
  	VideoCursOff();
  
     WindowSave( &Window, OldScrn );
  	PromptWindow( szText, NULL, GetPromptColor(), NULL );
  
  												/* Selection box doesn't need a shadow	*/
  	AddShadow = FALSE;					/* but the color has to be changed to	*/
  	OldBoxColor = GetBoxColor();		/* to match the prompt window color		*/
  	SetBoxColor( GetPromptColor() );
  
  	OldBarColor = GetBarColor();
  	SetBarColor( GetStatusColor() );
  	
  	i = MyGetSelection( Window.Top + i, 1, optdflt, szOpts );
  
  	SetBarColor( OldBarColor );
  	SetBoxColor( OldBoxColor );
  	AddShadow = TRUE;
  
     WindowRestore( &Window, OldScrn );
  	RestoreCursor( Cursor );
  	FreeMemory( OldScrn );
  
  	return( i );										/* Return user's selection		*/
  }
  
  