home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
pibterm
/
pibt41s3.arc
/
PIBMENUS.MOD
< prev
next >
Wrap
Text File
|
1988-02-07
|
43KB
|
911 lines
(*----------------------------------------------------------------------*)
(* PIBMENUS.PAS --- Menu Routines for Turbo Pascal *)
(*----------------------------------------------------------------------*)
(* *)
(* Author: Philip R. Burns *)
(* *)
(* Date: Version 1.0: January, 1985 *)
(* Version 1.1: March, 1985 *)
(* Version 1.2: May, 1985 *)
(* Version 2.0: June, 1985 *)
(* Version 2.1: July, 1985 *)
(* Version 3.0: October, 1985 *)
(* Version 3.2: November, 1985 *)
(* Version 4.0: March, 1986 *)
(* Version 4.1: February, 1987 *)
(* Version 4.2: March, 1987 *)
(* *)
(* Systems: For MS-DOS on IBM PCs and close compatibles only. *)
(* *)
(* History: These routines represent my substantial upgrading of the *)
(* simple menu routines written by Barry Abrahamsen which *)
(* I believe appeared originally in the TUG newsletter. *)
(* The windowing facility provides windows similar to those *)
(* implemented in QMODEM by John Friel III. *)
(* *)
(* Version 2.0 of these adds the exploding windows feature *)
(* as well the use-selectable box-drawing characters. *)
(* The exploding box algorithm is derived from one by *)
(* Jim Everingham. *)
(* *)
(* Note that the routines present in PIBSCREN.PAS were *)
(* originally part of the PIBMENUS.PAS file. With version *)
(* 2.0 of PibMenus, PIBMENUS.PAS is split into the screen- *)
(* handling routines in PIBSCREN.PAS and the actual menu *)
(* routines in PIBMENUS.PAS. *)
(* *)
(* Suggestions for improvements or corrections are welcome. *)
(* Please leave messages on Gene Plantz's BBS (312) 882 4145 *)
(* or Ron Fox's BBS (312) 940 6496. *)
(* *)
(* If you use this code in your own programs, please be nice *)
(* and give all of us credit. *)
(* *)
(*----------------------------------------------------------------------*)
(* *)
(* Needs: These routines need the include files MINMAX.PAS, *)
(* GLOBTYPE.PAS, ASCII.PAS, and PIBSCREN.PAS. These files *)
(* are not included here, since Turbo Pascal regrettably does *)
(* not allow nested includes. *)
(* *)
(*----------------------------------------------------------------------*)
(* *)
(* What these routines do: *)
(* *)
(* These routines provide a straight-forward menu-selection *)
(* facility, similar to that used in programs like Lotus. A pop-up *)
(* window holds the menu. The menu is contained in a frame. The *)
(* items are displayed within the frame. The currently selected *)
(* item is highlighted in reverse video. You move up and down in *)
(* the list of menu items by using the up and down arrow keys, or *)
(* the space bar. To make a selection, hit the Enter (Return) key. *)
(* *)
(* Alternatively, you may hit the first character of a menu item. *)
(* The first menu item found with that initial letter is selected. *)
(* *)
(* The characters comprising the menu box are user-selectable. *)
(* In addition, menus may just "pop up" onto the screen, or may *)
(* "explode" onto the screen. *)
(* *)
(* Hitting the escape key causes a menu choice of "-1" to be *)
(* returned to the calling routine. *)
(* *)
(*----------------------------------------------------------------------*)
(* *)
(* Use: *)
(* *)
(* (1) Define a variable of type Menu_Type, say, MYMENU. *)
(* *)
(* (2) Define the following entries in MYMENU: *)
(* *)
(* Menu_Size --- Number of entries in this menu *)
(* Menu_Title --- Title for the menu *)
(* Menu_Row --- Row where menu should appear (upper LHC *)
(* Menu_Column --- Column where menu should appear *)
(* Menu_Width --- Width of menu *)
(* Menu_Height --- Height of menu *)
(* Menu_Default --- Ordinal of the default menu entry *)
(* Menu_Tcolor --- Color to display menu text *)
(* Menu_Bcolor --- Color for menu background *)
(* Menu_Fcolor --- Color for menu frame box *)
(* *)
(* (3) Now for each of Menu_Size Menu_Entries, define: *)
(* Menu_Text --- Text of menu item *)
(* *)
(* (4) Optionally call Menu_Set_Box_Chars to define the *)
(* characters used to form the menu box. *)
(* *)
(* (5) Optionally call Menu_Set_Explode to set the menus as either *)
(* exploding or pop-up. *)
(* *)
(* (6) Optionally call Menu_Set_Beep to turn beeping on/off. *)
(* *)
(* (7) Call Menu_Display_Choices to display menu. The default *)
(* menu choice will be highlighted. *)
(* *)
(* (8) Call Menu_Get_Choice to retrieve menu choice. The up and *)
(* down arrows, and the space bar, can be used to move *)
(* through the menu items. Each item is highlighted in turn. *)
(* Whichever item is highlighted when a carriage return is *)
(* entered is returned as the chosen item. *)
(* *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_Set_Explode( Explode_ON : BOOLEAN );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_Set_Explode *)
(* *)
(* Purpose: Turn exploding menus on or off *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_Set_Explode( Explode_ON : BOOLEAN ); *)
(* *)
(* Explode_ON --- TRUE to use exploding menus, *)
(* FALSE to use pop-up menus *)
(* *)
(* Calls: None *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Menu_Set_Explode *)
Menu_Explode_Mode := Explode_ON;
END (* Menu_Set_Explode *);
(*----------------------------------------------------------------------*)
(* Menu_Set_Beep --- Set beep mode on or off *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_Set_Beep( Beep_ON : BOOLEAN );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_Set_Beep *)
(* *)
(* Purpose: Turn beeping (errors, etc.) on or off *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_Set_Beep( Beep_ON : BOOLEAN ); *)
(* *)
(* Beep_ON --- TRUE to allow beeps, *)
(* FALSE to disallow beeps. *)
(* *)
(* Calls: None *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Menu_Set_Beep *)
Menu_Beep_Mode := Beep_ON;
END (* Menu_Set_Beep *);
(*----------------------------------------------------------------------*)
(* Menu_Set_Box_Chars --- Set box drawing characters for menus *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_Set_Box_Chars( Top_Left_Corner : CHAR;
Top_Line : CHAR;
Top_Right_Corner : CHAR;
Right_Line : CHAR;
Bottom_Right_Corner : CHAR;
Bottom_Line : CHAR;
Bottom_Left_Corner : CHAR;
Left_Line : CHAR );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_Set_Box_Chars *)
(* *)
(* Purpose: Set box characters for drawing menu boxes *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_Set_Box_Chars( Top_Left_Corner : CHAR; *)
(* Top_Line : CHAR; *)
(* Top_Right_Corner : CHAR; *)
(* Right_Line : CHAR; *)
(* Bottom_Right_Corner : CHAR; *)
(* Bottom_Line : CHAR; *)
(* Bottom_Left_Corner : CHAR; *)
(* Left_Line : CHAR ); *)
(* *)
(* --- arguments are what their names suggest. *)
(* *)
(* *)
(* Calls: None *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Menu_Set_Box_Chars *)
Menu_Box_Chars.Top_Left_Corner := Top_Left_Corner;
Menu_Box_Chars.Top_Line := Top_Line;
Menu_Box_Chars.Top_Right_Corner := Top_Right_Corner;
Menu_Box_Chars.Right_Line := Right_Line;
Menu_Box_Chars.Bottom_Right_Corner := Bottom_Right_Corner;
Menu_Box_Chars.Bottom_Line := Bottom_Line;
Menu_Box_Chars.Bottom_Left_Corner := Bottom_Left_Corner;
Menu_Box_Chars.Left_Line := Left_Line;
END (* Menu_Set_Box_Chars *);
(*----------------------------------------------------------------------*)
(* Draw_Box --- Draw a box *)
(*----------------------------------------------------------------------*)
PROCEDURE Draw_Box( X1, Y1, X2, Y2 : INTEGER;
Frame_Color : INTEGER;
Title_Color : INTEGER;
Title : AnyStr );
VAR
I : INTEGER;
LT : INTEGER;
FColor: INTEGER;
BEGIN (* Draw_Box *)
LT := LENGTH( Title );
FColor := Frame_Color;
IF LT > 0 THEN
BEGIN
WriteSXY( Menu_Box_Chars.Top_Left_Corner + '[ ',
X1, Y1, FColor );
WriteSXY( Title, X1 + 3, Y1, Title_Color );
WriteSXY( ' ]', X1 + LT + 3, Y1, FColor );
END
ELSE
WriteSXY( Menu_Box_Chars.Top_Left_Corner +
DUPL( Menu_Box_Chars.Top_Line , 4 ), X1, Y1, FColor );
(* Draw remainder of top of frame *)
WriteSXY( Dupl( Menu_Box_Chars.Top_Line , X2 - X1 - LT - 5 ),
( X1 + LT + 5 ), Y1, FColor );
WriteCXY( Menu_Box_Chars.Top_Right_Corner, X2, Y1, FColor );
(* Draw sides of frame *)
FOR I := SUCC( Y1 ) TO PRED( Y2 ) DO
BEGIN
WriteCXY( Menu_Box_Chars.Left_Line, X1, I, FColor );
WriteCXY( Menu_Box_Chars.Right_Line, X2, I, FColor );
END;
(* Draw bottom of frame *)
WriteCXY( Menu_Box_Chars.Bottom_Left_Corner, X1, Y2, FColor );
WriteSXY( Dupl( Menu_Box_Chars.Bottom_Line , PRED( X2 - X1 ) ),
SUCC( X1 ), Y2, FColor );
WriteCXY( Menu_Box_Chars.Bottom_Right_Corner, X2, Y2, FColor );
END (* Draw_Box *);
(*----------------------------------------------------------------------*)
(* Draw_Menu_Frame --- Draw a Frame *)
(*----------------------------------------------------------------------*)
PROCEDURE Draw_Menu_Frame( UpperLeftX, UpperLeftY,
LowerRightX, LowerRightY : INTEGER;
Frame_Color, Title_Color,
Text_Color : INTEGER;
Menu_Title: AnyStr );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Draw_Menu_Frame *)
(* *)
(* Purpose: Draws a titled frame using PC graphics characters *)
(* *)
(* Calling Sequence: *)
(* *)
(* Draw_Menu_Frame( UpperLeftX, UpperLeftY, *)
(* LowerRightX, LowerRightY, *)
(* Frame_Color, Title_Color : INTEGER; *)
(* Menu_Title: AnyStr ); *)
(* *)
(* UpperLeftX, UpperLeftY --- Upper left coordinates *)
(* LowerRightX, LowerRightY --- Lower right coordinates *)
(* Frame_Color --- Color for frame *)
(* Title_Color --- Color for title text *)
(* Text_Color --- Color for interior text *)
(* Menu_Title --- Menu Title *)
(* *)
(* Calls: GoToXY *)
(* Dupl *)
(* Draw_Box *)
(* Do_Explosion (internal) *)
(* *)
(* Remarks: *)
(* *)
(* The area inside the frame is cleared after the frame is *)
(* drawn. If a box without a title is desired, enter a null *)
(* string for a title. *)
(* *)
(*----------------------------------------------------------------------*)
VAR
I : INTEGER;
L : INTEGER;
LT : INTEGER;
XM : INTEGER;
YM : INTEGER;
XS : INTEGER;
YS : INTEGER;
R : REAL;
X1 : INTEGER;
X2 : INTEGER;
Y1 : INTEGER;
Y2 : INTEGER;
XM1: INTEGER;
YM1: INTEGER;
Knt: INTEGER;
(*----------------------------------------------------------------------*)
(* Do_Explosion --- Draw an 'exploding' box *)
(*----------------------------------------------------------------------*)
PROCEDURE Do_Explosion;
(*----------------------------------------------------------------------*)
(* --- Basic algorithm by Jim Everingham --- *)
(*----------------------------------------------------------------------*)
VAR
I: INTEGER;
BEGIN (* Do_Explosion *)
XM := UpperLeftX + L SHR 1;
YM := UpperLeftY + ( LowerRightY - UpperLeftY ) SHR 1;
X1 := UpperLeftX;
X2 := LowerRightX;
Y1 := UpperLeftY;
Y2 := LowerRightY;
XM1 := XM;
YM1 := YM;
(* Figure out increments for *)
(* increasing boz dimensions *)
(* to produce explosion. *)
IF ( XM > YM ) THEN
Knt := L SHR 1
ELSE
Knt := ( Y2 - Y1 ) SHR 1;
Y1 := PRED( Y1 );
Y2 := PRED( Y2 );
X1 := SUCC( X1 );
X2 := PRED( X2 );
(* Draw series of increasing *)
(* size boxes, giving appearance *)
(* that box "explodes" from its *)
(* center. *)
FOR I := 1 TO ROUND( Knt / 3 ) DO
BEGIN
(* Adjust sides *)
IF ( XM > ( X1 - 2 ) ) THEN
XM := XM - 3
ELSE IF ( XM > PRED( X1 ) ) THEN
XM := XM - 2
ELSE IF ( XM > X1 ) THEN
XM := PRED( XM );
IF ( XM1 < ( X2 + 2 ) ) THEN
XM1 := XM1 + 3
ELSE IF ( XM1 < ( X2 + 1 ) ) THEN
XM1 := XM1 + 2
ELSE IF ( XM1 < X2 ) THEN
XM1 := SUCC( XM1 );
(* Adjust top and bottom *)
IF ( YM > ( Y1 + 2 ) ) THEN
YM := YM - 3
ELSE IF ( YM > ( Y1 + 1 ) ) THEN
YM := YM - 2
ELSE IF ( YM > Y1 ) THEN
YM := PRED( YM );
IF ( YM1 < ( Y2 - 2 ) ) THEN
YM1 := YM1 + 3
ELSE IF ( YM1 < PRED( Y2 ) ) THEN
YM1 := YM1 + 2
ELSE IF ( YM1 < Y2 ) THEN
YM1 := SUCC( YM1 );
(* Define new window *)
PibTerm_Window( SUCC( XM ), SUCC( YM ), XM1, YM1 );
(* Clear it out *)
Clear_Window;
(* Draw box *)
Draw_Box( SUCC( XM ), SUCC( YM ), MIN( LowerRightX , XM1 ),
YM1, Frame_Color, Title_Color, '' );
END (* FOR *);
END (* Do_Explosion *);
(*----------------------------------------------------------------------*)
BEGIN (* Draw_Menu_Frame *)
L := LowerRightX - UpperLeftX;
LT := LENGTH( Menu_Title );
(* Adjust title length if necessary *)
IF LT > ( L - 5 ) THEN Menu_Title[0] := CHR( L - 5 );
(* Get explosion if requested *)
IF Menu_Explode_Mode THEN Do_Explosion;
(* Display actual menu frame *)
Draw_Box( UpperLeftX, UpperLeftY, LowerRightX, LowerRightY,
Frame_Color, Title_Color, Menu_Title );
(* Establish scrolling window area *)
PibTerm_Window( UpperLeftX+1, UpperLeftY+1, LowerRightX-1, LowerRightY-1 );
(* Ensure proper color for text *)
TextColor ( Text_Color );
TextBackGround( BLACK );
(* Clear out the window area *)
(* KLUDGE NOTE: ClrScr doesn't *)
(* seem to work correctly on mono *)
(* screens with Turbo 3.0 in the *)
(* context of PibTerm. *)
{
GoToXY( 1 , 1 );
ClrScr;
}
FOR I := 1 TO PRED( LowerRightY - UpperLeftY ) DO
BEGIN
GoToXY( 1 , I );
ClrEol;
END;
GoToXY( 1 , 1 );
END (* Draw_Menu_Frame *);
(*----------------------------------------------------------------------*)
(* Menu_Click --- Make short click noise *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_Click;
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_Click *)
(* *)
(* Purpose: Clicks Terminal Bell *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_Click; *)
(* *)
(* Calls: Sound *)
(* Delay *)
(* NoSound *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Menu_Click *)
IF Menu_Beep_Mode THEN
BEGIN
Sound( 2000 );
DELAY( 10 );
NoSound;
END;
END (* Menu_Click *);
(*----------------------------------------------------------------------*)
(* Menu_Beep --- Ring Terminal Bell *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_Beep;
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_Beep *)
(* *)
(* Purpose: Rings Terminal Bell *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_Beep; *)
(* *)
(* Calls: None *)
(* *)
(* Remarks: *)
(* *)
(* If Menu_Beep_Mode is FALSE, then '<ALERT>' is displayed in *)
(* blinking characters on status line for 1 second *)
(* *)
(*----------------------------------------------------------------------*)
VAR
I : INTEGER;
J : INTEGER;
Save_C25 : PACKED ARRAY[1..7] OF CHAR;
Save_A25 : PACKED ARRAY[1..7] OF BYTE;
BEGIN (* Menu_Beep *)
(* Generate beep if beep mode on *)
IF Menu_Beep_Mode THEN
Sound_Bell
ELSE (* Else generate blinking error *)
BEGIN
(* Save character, attribute *)
FOR I := 1 TO 7 DO
ReadCXY( Save_C25[I], ( 35 + I ), Max_Screen_Line, Save_A25[I] );
(* Display blinking error indicator *)
WriteSXY( '<ALERT>', 36, Max_Screen_Line, WHITE + BLINK );
DELAY( One_Second_Delay );
(* Restore previous text *)
FOR I := 1 TO 7 DO
WriteCXY( Save_C25[I], ( 35 + I ), Max_Screen_Line, Save_A25[I] );
END;
END (* Menu_Beep *);
(*----------------------------------------------------------------------*)
(* Menu_Turn_On --- Highlight Menu Choice *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_Turn_On( Menu: Menu_Type; Menu_Item : INTEGER );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_Turn_On *)
(* *)
(* Purpose: Highlight a menu item using reverse video *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_Turn_On( Menu: Menu_Type; Menu_Item : INTEGER ); *)
(* *)
(* Menu : Menu containing item to highlight *)
(* Menu_Item : Menu entry to highlight *)
(* *)
(* Calls: GoToXY *)
(* RvsVideoOn *)
(* RvsVideoOff *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Menu_Turn_On *)
WITH Menu.Menu_Entries[ Menu_Item ] DO
BEGIN
GoToXY( Menu_Item_Column, Menu_Item_Row );
TextColor ( Menu.Menu_Bcolor );
TextBackGround( Menu.Menu_Tcolor );
WRITE( Menu_Item_Text );
TextColor ( Menu.Menu_Tcolor );
TextBackGround( Menu.Menu_Bcolor );
END;
END (* Menu_Turn_On *);
(*----------------------------------------------------------------------*)
(* Menu_Turn_Off --- UnHighlight Menu Choice *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_Turn_Off( Menu: Menu_Type; Menu_Item : INTEGER );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_Turn_Off *)
(* *)
(* Purpose: Removes highlighting from menu item *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_Turn_Off( Menu : Menu_Type; Menu_Item : INTEGER ); *)
(* *)
(* Menu : Menu containing item to unhighlight *)
(* RvsVideoOff : Menu entry to un-highlight *)
(* *)
(* Calls: GoToXY *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Menu_Turn_Off *)
WITH Menu.Menu_Entries[ Menu_Item ] DO
BEGIN
GoToXY( Menu_Item_Column , Menu_Item_Row );
TextColor ( Menu.Menu_TColor );
TextBackGround( Menu.Menu_BColor );
WRITE( Menu_Item_Text );
END;
END (* Menu_Turn_Off *);
(*----------------------------------------------------------------------*)
(* Menu_IBMCh --- Interpret IBM keyboard chars. *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_IBMCh( VAR C : CHAR );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_IBMCh *)
(* *)
(* Purpose: Interpret IBM keyboard chars. *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_IBMCh( Var C : Char ); *)
(* *)
(* C --- On input, char following escape; *)
(* on output, char revised to Wordstar command code. *)
(* *)
(* Calls: Read_Kbd_Old *)
(* *)
(*----------------------------------------------------------------------*)
BEGIN (* Menu_IBMCh *)
Read_Kbd_Old( C );
CASE ORD( C ) OF
U_Arrow : C := Up_Arrow;
D_Arrow : C := Down_Arrow;
L_Arrow : C := Left_Arrow;
R_Arrow : C := Right_Arrow;
ELSE
C := CHR( ESC );
END;
END (* Menu_IBMCh *);
(*----------------------------------------------------------------------*)
(* Menu_Display_Choices --- Display Menu Choices *)
(*----------------------------------------------------------------------*)
PROCEDURE Menu_Display_Choices( Menu : Menu_Type );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Menu_Display_Choices *)
(* *)
(* Purpose: Displays Menu Choices *)
(* *)
(* Calling Sequence: *)
(* *)
(* Menu_Display_Choices( Menu : Menu_Type ); *)
(* *)
(* Menu --- Menu record to be displayed. *)
(* *)
(* Calls: ClsScr *)
(* GoToXY *)
(* Draw_Menu_Frame *)
(* Save_Screen *)
(* *)
(*----------------------------------------------------------------------*)
VAR
I : INTEGER;
J : INTEGER;
XL : INTEGER;
YL : INTEGER;
XR : INTEGER;
YR : INTEGER;
MaxX : INTEGER;
MaxY : INTEGER;
BEGIN (* Menu_Display_Choices *)
(* Establish menu size *)
XL := Menu.Menu_Column;
YL := Menu.Menu_Row;
XR := PRED( LENGTH( Menu.Menu_Title ) + XL );
YR := YL;
MaxX := MAX( Menu.Menu_Width , ( LENGTH( Menu.Menu_Title ) + 2 ) );
MaxY := Menu.Menu_Height;
FOR I := 1 TO Menu.Menu_Size DO
WITH Menu.Menu_Entries[I] DO
BEGIN
IF Menu_Item_Row > MaxY THEN MaxY := Menu_Item_Row;
J := PRED( LENGTH( Menu_Item_Text ) + Menu_Item_Column );
IF J > MaxX THEN MaxX := J;
END;
J := PRED( XL + MaxX );
IF J > XR THEN XR := J;
J := PRED( YL + MaxY );
IF J > YR THEN YR := J;
XL := XL - 4;
IF XL < 0 THEN XL := 0;
YL := PRED( YL );
IF YL < 0 THEN YL := 0;
YR := SUCC( YR );
IF YR > Max_Screen_Line THEN YR := Max_Screen_Line;
IF XR > Max_Screen_Col THEN XR := Max_Screen_Col;
(* Save current screen image *)
(* if not already saved *)
IF Current_Saved_Screen > 0 THEN
BEGIN
IF Saved_Screen_List[ Current_Saved_Screen ] <> Saved_Screen THEN
Save_Partial_Screen( Saved_Screen, XL, YL, XR, YR );
END
ELSE
Save_Partial_Screen( Saved_Screen, XL, YL, XR, YR );
(* Draw the menu frame *)
Draw_Menu_Frame( XL, YL, XR, YR, Menu.Menu_FColor, Menu.Menu_HColor,
Menu.Menu_TColor, Menu.Menu_Title );
(* Display Menu Entries *)
FOR I := 1 TO Menu.Menu_Size DO
WITH Menu.Menu_Entries[I] DO
BEGIN
GoToXY( Menu_Item_Column , Menu_Item_Row );
WRITE( Menu_Item_Text );
END;
(* Highlight Default Choice *)
Menu_Turn_On( Menu, Menu.Menu_Default );
END (* Menu_Display_Choices *);
(*----------------------------------------------------------------------*)
(* Menu_Get_Choice --- Get Menu Choice *)
(*----------------------------------------------------------------------*)
FUNCTION Menu_Get_Choice( Menu: Menu_Type; Erase_After: BOOLEAN ) : INTEGER;
(*----------------------------------------------------------------------*)
(* *)
(* Function: Menu_Get_Choice *)
(* *)
(* Purpose: Retrieves Menu Choice from current menu *)
(* *)
(* Calling Sequence: *)
(* *)
(* Ichoice := Menu_Get_Choice( Menu : Menu_Type; *)
(* Erase_After: BOOLEAN ) : INTEGER; *)
(* *)
(* Menu --- Currently displayed menu *)
(* Erase_After --- TRUE to erase menu after choice found *)
(* Ichoice --- Returned menu item chosen *)
(* *)
(* Calls: Menu_Click *)
(* Menu_IBMCh *)
(* Menu_Turn_Off *)
(* Menu_Turn_On *)
(* *)
(* Remarks: *)
(* *)
(* The current menu item is highlighted in reverse video. *)
(* It may be chosen by hitting the return key. Movement *)
(* to other menu items is done using the up-arrow and *)
(* down-arrow. *)
(* *)
(* An item may also be chosen by hitting the first character *)
(* of that item. *)
(* *)
(*----------------------------------------------------------------------*)
VAR
C : CHAR;
Current : INTEGER;
Last : INTEGER;
I : INTEGER;
Found : BOOLEAN;
BEGIN (* Menu_Get_Choice *)
(* Increase menu depth *)
INC( Menu_Depth );
(* Get default *)
Current := Menu.Menu_Default;
Last := PRED( Current );
IF Last < 1 THEN Last := Menu.Menu_Size;
REPEAT (* Loop until return key hit *)
(* Read a character *)
Read_Kbd_Old( C );
Menu_Click;
C := UpCase( C );
(* Convert character to menu code *)
IF ( C = Ch_Esc ) AND PibTerm_KeyPressed THEN
Menu_IBMCh( C );
(* Process character *)
CASE C OF
Down_Arrow,
Right_Arrow,
Space_Bar : BEGIN (* Move down menu *)
Last := Current;
INC( Current );
IF Current > Menu.Menu_Size THEN
Current := 1;
END;
Left_Arrow,
Up_Arrow : BEGIN (* Move up menu *)
Last := Current;
DEC( Current );
IF Current < 1 THEN
Current := Menu.Menu_Size;
END (* Move up menu *);
Ch_Cr : ;
Ch_Esc : Current := -1;
ELSE
Found := FALSE;
FOR I := 1 TO Menu.Menu_Size DO
IF C = UpCase( Menu.Menu_Entries[I].Menu_Item_Text[1] ) THEN
BEGIN
Found := TRUE;
C := Ch_Cr;
Last := Current;
Current := I;
END;
IF ( NOT Found ) THEN Menu_Beep;
END (* CASE *);
(* Highlight new menu choice *)
IF C IN [ Up_Arrow, Down_Arrow, Left_Arrow, Right_Arrow,
Space_Bar, Ch_Cr ] THEN
BEGIN
Menu_Turn_Off( Menu, Last );
Menu_Turn_On ( Menu, Current );
END;
UNTIL ( C = Ch_CR ) OR ( C = Ch_Esc );
(* Return index of chosen value *)
Menu_Get_Choice := Current;
(* Erase menu from display *)
IF Erase_After THEN
Restore_Screen_And_Colors( Saved_Screen );
(* Decrease menu depth *)
Menu_Depth := MAX( PRED( Menu_Depth ) , 0 );
END (* Menu_Get_Choice *);