home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 16 / 16.iso / w / w048 / 2.ddi / MSSRC.ARC / MSMENU.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1987-12-21  |  25.6 KB  |  818 lines

  1. {                            MSMENU.PAS
  2.                                MS 4.0
  3.                 Copyright (c) 1985, 87 by Borland International, Inc.         }
  4.  
  5. {$I msdirect.inc}
  6.  
  7. unit MsMenu;
  8.   {-Pulldown and custom menu systems}
  9.  
  10. interface
  11.  
  12. uses
  13.   Crt,                       {Basic video operations - standard unit}
  14.   Dos,                       {DOS interface - standard unit}
  15.   Errors,                    {Runtime error handler}
  16.   MsVars,                    {Global types and declarations}
  17.   MsScrn1,                   {Fast screen writing routines}
  18.   MsString,                  {String primitives}
  19.   MsPtrOp,                   {Pointer primitives}
  20.   EscSeq,                    {Returns text string for extended scan codes}
  21.   MsCmds,                    {Maps keystrokes to commands}
  22.   Int24,                     {DOS critical error handler}
  23.   Message,                   {Message system}
  24.   MsUser,                    {User keyboard input, line edit, error report, help}
  25.   MsBack,                    {Background processes}
  26.   MsScrn2;                   {Editor screen updating}
  27.  
  28. procedure EdGetCustomMenuChoice(var Menu : CustomMenuRec; var Choice : Integer);
  29.   {-Display a custom menu, get selection, dispose of menu, and return choice}
  30.  
  31. procedure EdGetMenuChoice(var Cmd : CommandType; var ExitMenu : Boolean);
  32.   {-Display the menu system, and get a selection}
  33.  
  34.   {==========================================================================}
  35.  
  36. implementation
  37.  
  38.   procedure EdGetCustomMenuChoice(var Menu : CustomMenuRec;
  39.                                   var Choice : Integer);
  40.     {-Display a custom menu, get selection, dispose of menu, and return choice}
  41.   var
  42.     Quitting, UseWindow : Boolean;
  43.     Ch : Char;
  44.     CheckChoice : Integer;
  45.     Wmenu : WindowRec;
  46.     LetterSet : Charset;
  47.  
  48.     procedure EdSetMaxCoords(var Menu : CustomMenuRec);
  49.       {-Compute the max x and y coordinates of the window}
  50.     var
  51.       MsgLen, PromptLen, Wid : Integer;
  52.  
  53.       function EdGetMaxStrLen(var Messages : MenuArrayPtr; MinChoice, MaxChoice : Integer) : Integer;
  54.         {-Return the longest string length in the menu}
  55.       var
  56.         Item : Integer;
  57.         Maxlen, Len : Integer;
  58.  
  59.       begin                  {EdGetMaxStrLen}
  60.         Maxlen := 0;
  61.         for Item := MinChoice to MaxChoice do begin
  62.           Len := Length(Messages^[Item]^);
  63.           if Len > Maxlen then
  64.             Maxlen := Len;
  65.         end;
  66.         EdGetMaxStrLen := Maxlen;
  67.       end;                   {EdGetMaxStrLen}
  68.  
  69.     begin                    {EdSetMaxCoords}
  70.       with Menu do begin
  71.         MsgLen := EdGetMaxStrLen(Messages, MinChoice, MaxChoice);
  72.         PromptLen := Length(EdGetMessage(PromptNum));
  73.         if MsgLen > PromptLen then
  74.           Wid := MsgLen
  75.         else
  76.           Wid := PromptLen;
  77.         Xmax := Xmin+Wid+3;
  78.         Ymax := Ymin+(MaxChoice-MinChoice)+2;
  79.       end;
  80.     end;                     {EdSetMaxCoords}
  81.  
  82.     procedure EdBuildLetterSet(var Menu : CustomMenuRec; var LetterSet : Charset);
  83.       {-Build a set of characters comprising the first letter of each menu selection}
  84.     var
  85.       Item : Integer;
  86.  
  87.     begin                    {EdBuildLetterSet}
  88.       LetterSet := [];
  89.       with Menu do
  90.         for Item := MinChoice to MaxChoice do
  91.           LetterSet := LetterSet+[Upcase(EdFirstLetter(Messages^[Item]^))];
  92.     end;                     {EdBuildLetterSet}
  93.  
  94.     procedure EdWriteEntry(var Menu : CustomMenuRec; var W : WindowRec; Item : Integer; Selected : Boolean);
  95.       {-Write one menu entry}
  96.     var
  97.       X, Y, Posn : Integer;
  98.       S : VarString;
  99.  
  100.     begin                    {EdWriteEntry}
  101.       if UseWindow then
  102.         with W, Menu do begin
  103.           S := EdPadEntry(Messages^[Item]^, XSize-2);
  104.           X := Succ(XPosn);
  105.           Y := YPosn+Succ(Item-MinChoice);
  106.           if Selected then
  107.             EdFastWrite(S, Y, X, ScreenAttr[MsColor])
  108.           else if UseLetters then begin
  109.             {Highlight the first non-blank character}
  110.             Posn := 1;
  111.             while S[Posn] = Blank do
  112.               Inc(Posn);
  113.             if Posn > 1 then
  114.               EdFastWrite(Copy(S, 1, Pred(Posn)), Y, X, ScreenAttr[MnColor]);
  115.             EdFastWrite(S[Posn], Y, X+Pred(Posn), ScreenAttr[MhColor]);
  116.             EdFastWrite(Copy(S, Succ(Posn), PhyScrCols), Y, X+Posn, ScreenAttr[MnColor]);
  117.           end else
  118.             EdFastWrite(S, Y, X, ScreenAttr[MnColor]);
  119.         end;
  120.     end;                     {EdWriteEntry}
  121.  
  122.     procedure EdDrawAllChoices(var Menu : CustomMenuRec; var W : WindowRec; MinChoice, MaxChoice, SelectNum : Integer);
  123.       {-Draw all of the filename choices}
  124.     var
  125.       Item : Integer;
  126.  
  127.     begin                    {EdDrawAllChoices}
  128.       for Item := MinChoice to MaxChoice do
  129.         EdWriteEntry(Menu, W, Item, (Item = SelectNum));
  130.     end;                     {EdDrawAllChoices}
  131.  
  132.     function EdLetterPos(var Menu : CustomMenuRec; Ch : Char) : Integer;
  133.       {-Return the choice number corresponding to ch}
  134.     var
  135.       Item : Integer;
  136.  
  137.     begin                    {EdLetterPos}
  138.       with Menu do
  139.         for Item := MinChoice to MaxChoice do
  140.           if Ch = Upcase(EdFirstLetter(Messages^[Item]^)) then begin
  141.             EdLetterPos := Item;
  142.             Exit;
  143.           end;
  144.     end;                     {EdLetterPos}
  145.  
  146.     procedure EdDisposeCustomMenu(var Menu : CustomMenuRec);
  147.       {-Release the heap space used by the menu}
  148.     var
  149.       Item : Integer;
  150.  
  151.     begin                    {EdDisposeCustomMenu}
  152.       with Menu do begin
  153.         {Release the strings}
  154.         for Item := MinChoice to MaxChoice do
  155.           FreeMem(Messages^[Item], Succ(Length(Messages^[Item]^)));
  156.         {Release the pointers to strings}
  157.         FreeMem(Messages, Succ(MaxChoice) shl 2);
  158.       end;
  159.     end;                     {EdDisposeCustomMenu}
  160.  
  161.   begin                      {EdGetCustomMenuChoice}
  162.  
  163.     AbortEnable := True;
  164.  
  165.     {Draw on screen only if not within a macro}
  166.     UseWindow := (EditUsercommandInput = 0);
  167.  
  168.     {Compute maximum window coordinates}
  169.     EdSetMaxCoords(Menu);
  170.  
  171.     with Menu do begin
  172.  
  173.       if UseLetters then
  174.         {Build a character set from the first letters of the menu strings}
  175.         EdBuildLetterSet(Menu, LetterSet)
  176.       else
  177.         LetterSet := [];
  178.  
  179.       {Put up a menu of selections}
  180.       if UseWindow then begin
  181.         EdSaveTextWindow(Border, EdGetMessage(PromptNum), Xmin, Ymin, Xmax, Ymax, Wmenu);
  182.         EdEraseMenuHelp;
  183.         EdWritePromptLine(EdGetMessage(MessageNum));
  184.         EdSetCursor(CursorOff);
  185.       end;
  186.       Choice := InitChoice;
  187.       EdDrawAllChoices(Menu, Wmenu, MinChoice, MaxChoice, Choice);
  188.  
  189.       {Select until done}
  190.       Quitting := False;
  191.       repeat
  192.  
  193.         EdWriteEntry(Menu, Wmenu, Choice, True);
  194.  
  195.         Ch := EdGetCursorCommand(CmdSet+LetterSet);
  196.  
  197.         if (Ch in LetterSet) then begin
  198.  
  199.           {Selection matches first letter of command}
  200.           Choice := EdLetterPos(Menu, Ch);
  201.           Quitting := True;
  202.  
  203.         end else
  204.           case Ch of
  205.  
  206.             '0'..'9' :       {Select by number}
  207.               begin
  208.                 CheckChoice := (Ord(Ch)-48);
  209.                 if (CheckChoice >= MinChoice) and (CheckChoice <= MaxChoice) then begin
  210.                   Quitting := True;
  211.                   Choice := CheckChoice;
  212.                 end;
  213.               end;
  214.  
  215.             ^J :             {Help on current topic}
  216.               begin
  217.                 EdHelpWindow(GlobalCmd);
  218.                 if UseWindow then begin
  219.                   {Assure hardware cursor is off again}
  220.                   EdSetCursor(CursorOff);
  221.                   {Assure prompt message is redisplayed}
  222.                   EdWritePromptLine(EdGetMessage(MessageNum));
  223.                 end;
  224.               end;
  225.  
  226.             ^M :             {Select current}
  227.               Quitting := True;
  228.  
  229.             ^[ :             {Escape}
  230.               Abortcmd := True;
  231.  
  232.             ^E :             {Scroll up}
  233.               begin
  234.                 EdWriteEntry(Menu, Wmenu, Choice, False);
  235.                 if Choice > MinChoice then
  236.                   Dec(Choice)
  237.                 else
  238.                   Choice := MaxChoice;
  239.               end;
  240.  
  241.             ^X :             {Scroll down}
  242.               begin
  243.                 EdWriteEntry(Menu, Wmenu, Choice, False);
  244.                 if Choice < MaxChoice then
  245.                   Inc(Choice)
  246.                 else
  247.                   Choice := MinChoice;
  248.               end;
  249.  
  250.           end;
  251.       until Abortcmd or Quitting;
  252.  
  253.       if not(Abortcmd) then
  254.         {Save the choice as an initial one for next time}
  255.         InitChoice := Choice;
  256.  
  257.       if UseWindow then
  258.         {Restore the screen}
  259.         EdRestoreTextWindow(Wmenu);
  260.  
  261.       {Dispose of the custom menu heap space}
  262.       EdDisposeCustomMenu(Menu);
  263.  
  264.     end;
  265.   end;                       {EdGetCustomMenuChoice}
  266.  
  267.   procedure EdGetMenuChoice(var Cmd : CommandType; var ExitMenu : Boolean);
  268.     {-Display the menu system, and get a selection}
  269.   type
  270.     {Available commands when menu selection is being made}
  271.     MenuCommandType = (Mup, Mdown, Mright, Mleft, Mesc, Msel, Mhelp, Mnul);
  272.   var
  273.     Ch : Char;
  274.     Mcmd : MenuCommandType;
  275.     Done : Boolean;
  276.     Sub : Byte;
  277.  
  278.     function EdMenuCommand(CurrMenu : Menuptr;
  279.                            var Ch : Char;
  280.                            var Mcmd : MenuCommandType) : Boolean;
  281.       {-Return a menucommand or a character}
  282.     const
  283.       WScommands : string[6] = ^@^D^E^S^X^J;
  284.       EXcommands : string[5] = 'MHKP;';
  285.     var
  286.       Orient : MenuOrientation;
  287.       Lev : Integer;
  288.  
  289.     begin                    {EdMenuCommand}
  290.       EdMenuCommand := True;
  291.       {Get the orientation of the current menu}
  292.       Lev := CurrMenu^.MenuLev;
  293.       Orient := MenuDesc[Lev].Orientation;
  294.       Mcmd := Mnul;
  295.  
  296.       Ch := EdGetAnyChar;
  297.       if Ch = Null then
  298.         {Extended character, get other half and convert to WS format}
  299.         Ch := WScommands[Succ(Pos(EdGetAnyChar, EXcommands))];
  300.  
  301.       case Ch of
  302.         ^J :                 {F1}
  303.           Mcmd := Mhelp;
  304.         ^E :                 {Up arrow}
  305.           if Orient = Vertical then
  306.             Mcmd := Mup;
  307.         ^X :                 {Down arrow}
  308.           if Lev = 1 then
  309.             Mcmd := Msel
  310.           else if Orient = Vertical then
  311.             Mcmd := Mdown;
  312.         ^S :                 {Left arrow}
  313.           if Lev <= 2 then
  314.             Mcmd := Mleft;
  315.         ^D :                 {Right arrow}
  316.           if Lev <= 2 then
  317.             Mcmd := Mright;
  318.         ^M :                 {Enter}
  319.           Mcmd := Msel;
  320.         ^[ :                 {Esc}
  321.           Mcmd := Mesc;
  322.       else
  323.         {Can't be a menu command}
  324.         EdMenuCommand := False;
  325.       end;
  326.     end;                     {EdMenuCommand}
  327.  
  328.     function EdMenuSelection(CurrMenu : Menuptr; Ch : Char; var Sub : Byte) : Boolean;
  329.       {-Return true and a submenu number if ch matches a select character}
  330.     var
  331.       Found : Boolean;
  332.  
  333.     begin                    {EdMenuSelection}
  334.       with CurrMenu^ do begin
  335.         Ch := Upcase(Ch);
  336.         Sub := 1;
  337.         Found := False;
  338.         while not(Found) and (Sub <= SubMax) do begin
  339.           with SubMenus^[Sub] do
  340.             Found := EdCmdAccessible(CurrMenu, Sub) and
  341.             (Upcase(Prompt^[Soffset]) = Ch);
  342.           if not(Found) then
  343.             Inc(Sub);
  344.         end;
  345.       end;
  346.       EdMenuSelection := Found;
  347.     end;                     {EdMenuSelection}
  348.  
  349.     procedure EdUpdateItem(Menu : Menuptr; SubLast, SubCur : Byte);
  350.       {-Highlight the current menu item}
  351.  
  352.     begin                    {EdUpdateItem}
  353.       EdDrawItem(Menu, SubLast);
  354.       EdDrawItem(Menu, SubCur);
  355.     end;                     {EdUpdateItem}
  356.  
  357.     procedure EdDecCurSubmenu(Menu : Menuptr);
  358.       {-Move to the previous selection, and wrap}
  359.     var
  360.       SubLast : Byte;
  361.  
  362.     begin                    {EdDecCurSubmenu}
  363.       with Menu^ do begin
  364.         SubLast := SubCur;
  365.         repeat
  366.           if SubCur > 1 then
  367.             Dec(SubCur)
  368.           else
  369.             SubCur := SubMax;
  370.         until EdCmdAccessible(Menu, SubCur);
  371.         EdUpdateItem(Menu, SubLast, SubCur);
  372.       end;
  373.     end;                     {EdDecCurSubmenu}
  374.  
  375.     procedure EdIncCurSubmenu(Menu : Menuptr);
  376.       {-Move to the next selection, and wrap}
  377.     var
  378.       SubLast : Byte;
  379.  
  380.     begin                    {EdIncCurSubmenu}
  381.       with Menu^ do begin
  382.         SubLast := SubCur;
  383.         repeat
  384.           if SubCur < SubMax then
  385.             Inc(SubCur)
  386.           else
  387.             SubCur := 1;
  388.         until EdCmdAccessible(Menu, SubCur);
  389.         EdUpdateItem(Menu, SubLast, SubCur);
  390.       end;
  391.     end;                     {EdIncCurSubmenu}
  392.  
  393.     procedure EdSetInitSelection(CurrMenu : Menuptr);
  394.       {-Assure initial menu selection is accessible}
  395.  
  396.     begin                    {EdSetInitSelection}
  397.       with CurrMenu^ do begin
  398.         if SubCur < 1 then
  399.           SubCur := 1;
  400.         while not(EdCmdAccessible(CurrMenu, SubCur)) do
  401.           if SubCur < SubMax then
  402.             Inc(SubCur)
  403.           else
  404.             SubCur := 1;
  405.       end;
  406.     end;                     {EdSetInitSelection}
  407.  
  408.     procedure EdDisplayKeys(Cmd : CommandType);
  409.       {-Write a text representation of command keystrokes to status line}
  410.     var
  411.       Kptr : Integer;
  412.       Special : Boolean;
  413.       Dis, Keys : VarString;
  414.  
  415.     begin                    {EdDisplayKeys}
  416.       if EdKeyInterrupt then
  417.         Exit;
  418.       Keys := EdCommandKeys(Cmd, Primary);
  419.       EdClearString(Dis);
  420.       Kptr := 1;
  421.       while Kptr <= Length(Keys) do
  422.         Dis := Dis+EdTextRepresentation(Keys, Kptr, Special);
  423.       EdWritePromptLine(Dis);
  424.     end;                     {EdDisplayKeys}
  425.  
  426.     function EdEvaluateMenuCommand(var CurrMenu : Menuptr;
  427.                                    Mcmd : MenuCommandType;
  428.                                    var Cmd : CommandType) : Boolean;
  429.       {-Change current selection and current menu as indicated}
  430.     var
  431.       Done : Boolean;
  432.       Ch : Char;
  433.  
  434.     begin
  435.       Done := False;
  436.  
  437.       case Mcmd of
  438.  
  439.         Mleft :
  440.           begin
  441.             {Move the root menu selection left}
  442.             EdDecCurSubmenu(RootMenu);
  443.             if CurrMenu <> RootMenu then begin
  444.               EdUndrawMenu(CurrMenu);
  445.               with RootMenu^ do
  446.                 CurrMenu := SubMenus^[SubCur].SubMenu;
  447.               EdSetInitSelection(CurrMenu);
  448.               EdDrawMenu(CurrMenu);
  449.             end;
  450.           end;
  451.  
  452.         Mright :
  453.           begin
  454.             {Move the root menu selection right}
  455.             EdIncCurSubmenu(RootMenu);
  456.             if CurrMenu <> RootMenu then begin
  457.               EdUndrawMenu(CurrMenu);
  458.               with RootMenu^ do
  459.                 CurrMenu := SubMenus^[SubCur].SubMenu;
  460.               EdSetInitSelection(CurrMenu);
  461.               EdDrawMenu(CurrMenu);
  462.             end;
  463.           end;
  464.  
  465.         Mup :
  466.           {Move the current menu selection up}
  467.           EdDecCurSubmenu(CurrMenu);
  468.  
  469.         Mdown :
  470.           {Move the current menu selection down}
  471.           EdIncCurSubmenu(CurrMenu);
  472.  
  473.         Mesc :
  474.           if CurrMenu = RootMenu then begin
  475.             {Leave the menu system}
  476.             Done := True;
  477.             if WindowCount > 0 then
  478.               EdEraseMenus;
  479.             Cmd := CmdNull;
  480.           end else begin
  481.             EdUndrawMenu(CurrMenu);
  482.             if CurrMenu^.MenuLev = 2 then
  483.               {Move back to the root menu}
  484.               CurrMenu := RootMenu
  485.             else
  486.               with RootMenu^ do
  487.                 {Move back to level 2}
  488.                 CurrMenu := SubMenus^[SubCur].SubMenu;
  489.             CurrMenu^.SubOn := False;
  490.           end;
  491.  
  492.         Msel :
  493.           with CurrMenu^ do
  494.             if EdPtrNotNil(SubMenus^[SubCur].SubMenu) then begin
  495.               {Another menu below, display it and move to it}
  496.               SubOn := True;
  497.               CurrMenu := SubMenus^[SubCur].SubMenu;
  498.               EdSetInitSelection(CurrMenu);
  499.               EdDrawMenu(CurrMenu);
  500.             end else begin
  501.               {Bottom level menu, return a command}
  502.               Done := True;
  503.               Cmd := SubMenus^[SubCur].Command;
  504.             end;
  505.  
  506.         Mhelp :
  507.           with CurrMenu^ do begin
  508.             Cmd := SubMenus^[SubCur].Command;
  509.             if (Cmd <> CmdNull) and (Cmd <> CmdNullMain) then begin
  510.               EdHelpWindow(Cmd);
  511.               if SaveKeyHelpMode then
  512.                 {Redisplay the keystrokes as a helpful prompt}
  513.                 EdDisplayKeys(Cmd);
  514.             end else
  515.               EdDisplayPromptWindow(
  516.                                     EdGetMessage(55)+'-'+EdGetMessage(305), 13, [#27], Ch, NormalBox);
  517.             EdSetCursor(CursorOff);
  518.           end;
  519.  
  520.       end;
  521.       EdEvaluateMenuCommand := Done;
  522.     end;                     {EdEvaluateMenuCommand}
  523.  
  524.     function EdEvaluateSelectionCommand(var CurrMenu : Menuptr;
  525.                                         Sub : Byte;
  526.                                         var Cmd : CommandType) : Boolean;
  527.       {-Select from the menu based on a prompt character}
  528.     var
  529.       Done : Boolean;
  530.       SubLast : Byte;
  531.  
  532.     begin                    {EdEvaluateSelectionCommand}
  533.       Done := False;
  534.       with CurrMenu^ do begin
  535.         SubLast := SubCur;
  536.         if EdPtrNotNil(SubMenus^[Sub].SubMenu) then begin
  537.           {Open up the selected submenu}
  538.           SubCur := Sub;
  539.           SubOn := True;
  540.           {Update the screen}
  541.           EdUpdateItem(CurrMenu, SubLast, SubCur);
  542.           CurrMenu := SubMenus^[SubCur].SubMenu;
  543.           EdSetInitSelection(CurrMenu);
  544.           EdDrawMenu(CurrMenu);
  545.         end else begin
  546.           {Accept the command}
  547.           Done := True;
  548.           SubCur := Sub;
  549.           {Update the screen}
  550.           EdUpdateItem(CurrMenu, SubLast, SubCur);
  551.           Cmd := SubMenus^[SubCur].Command;
  552.         end;
  553.       end;
  554.       EdEvaluateSelectionCommand := Done;
  555.     end;                     {EdEvaluateSelectionCommand}
  556.  
  557.   begin                      {EdGetMenuChoice}
  558.  
  559.     EdSetCursor(CursorOff);
  560.     EdEraseMenuHelp;
  561.  
  562.     if EdPtrIsNil(CurrMenu) then
  563.       CurrMenu := RootMenu;
  564.  
  565.     {Set the initial menu selection to an acceptable one}
  566.     EdSetInitSelection(CurrMenu);
  567.  
  568.     if CurrMenu = RootMenu then
  569.       EdDrawMenu(CurrMenu)
  570.     else
  571.       {Menu already on screen, just update the items}
  572.       for Sub := 1 to CurrMenu^.SubMax do
  573.         EdDrawItem(CurrMenu, Sub);
  574.  
  575.     Done := False;
  576.  
  577.     repeat
  578.  
  579.       if SaveKeyHelpMode then
  580.         {Display the keystrokes as a helpful prompt}
  581.         with CurrMenu^ do
  582.           EdDisplayKeys(SubMenus^[SubCur].Command);
  583.  
  584.       if EdMenuCommand(CurrMenu, Ch, Mcmd) then
  585.         {Move the cursor, escape, or select the current submenu}
  586.         Done := EdEvaluateMenuCommand(CurrMenu, Mcmd, Cmd)
  587.  
  588.       else if EdMenuSelection(CurrMenu, Ch, Sub) then
  589.         {Select an entry by letter}
  590.         Done := EdEvaluateSelectionCommand(CurrMenu, Sub, Cmd);
  591.  
  592.     until Done;
  593.  
  594.     {Should the menus stay on-screen?}
  595.     if (Cmd = CmdNull) and (WindowCount = 0) then
  596.       ExitMenu := False
  597.     else
  598.       ExitMenu := not(Cmd in StayCommands);
  599.  
  600.     if ExitMenu and not(SolidCursor) then
  601.       EdUpdateCursor;
  602.  
  603.   end;                       {EdGetMenuChoice}
  604.  
  605. type
  606.   InitArray = array[1..MaxInt] of Byte;
  607.   InitArrayPtr = ^InitArray;
  608.  
  609.   {$L MSMENU}
  610.  
  611.   function EdGetMenuInitPtr : InitArrayPtr; external;
  612.   {-Return a pointer to the menu initialization data}
  613.  
  614.   procedure EdInitMenus;
  615.     {-Set up the dynamic data structure of the menus}
  616.   var
  617.     P : InitArrayPtr;
  618.     InitPos, Smax, I : Integer;
  619.     Tmenu : Menuptr;
  620.  
  621.     procedure EdInitMenuDesc(var MenuDesc : Menulevels);
  622.       {-Initialize general descriptions of each level of menu}
  623.     const
  624.       RootBorder : BorderChars = '┌┐└┘─│├┤';
  625.       SubBorder : BorderChars = '┬┬└┘─│├┤';
  626.  
  627.     begin                    {Edinitmenudesc}
  628.       with MenuDesc[1] do begin
  629.         Border := RootBorder;
  630.         Orientation := Horizontal;
  631.         EdSetPtrNil(Overlap);
  632.       end;
  633.       with MenuDesc[2] do begin
  634.         Border := SubBorder;
  635.         Orientation := Vertical;
  636.         EdSetPtrNil(Overlap);
  637.       end;
  638.       with MenuDesc[3] do begin
  639.         Border := RootBorder;
  640.         Orientation := Vertical;
  641.         EdSetPtrNil(Overlap);
  642.       end;
  643.     end;                     {EdInitMenuDesc}
  644.  
  645.     function EdGetInitByte(P : InitArrayPtr; var InitPos : Integer) : Byte;
  646.       {-Return the next byte from the menu initialization data}
  647.  
  648.     begin                    {EdGetInitByte}
  649.       EdGetInitByte := P^[InitPos];
  650.       Inc(InitPos);
  651.     end;                     {EdGetInitByte}
  652.  
  653.     procedure EdInitMenu(P : InitArrayPtr; var InitPos, Smax : Integer; var Tmenu : Menuptr);
  654.       {-Initialize the parameters of one menu level}
  655.     var
  656.       Lev, Xp, Yp, Xs, Ys : Byte;
  657.       Smenu : Menuptr;
  658.  
  659.       procedure EdError(msg : VarString);
  660.         {-Halt in case of error during initialization}
  661.       begin                  {EdError}
  662.         Write(^M^J, msg);
  663.         Halt(1);
  664.       end;                   {EdError}
  665.  
  666.     begin                    {EdInitMenu}
  667.  
  668.       {Get the next six bytes from the initialization data}
  669.       Lev := EdGetInitByte(P, InitPos);
  670.       Xp := EdGetInitByte(P, InitPos);
  671.       Yp := EdGetInitByte(P, InitPos);
  672.       Xs := EdGetInitByte(P, InitPos);
  673.       Ys := EdGetInitByte(P, InitPos);
  674.       Smax := EdGetInitByte(P, InitPos);
  675.  
  676.       if Smax = 0 then
  677.         {No items in this menu}
  678.         EdSetPtrNil(Tmenu)
  679.       else begin
  680.         {Get the menu record and initialize it}
  681.         if EdMemAvail(SizeOf(Menuptr), FreeListPerm) then
  682.           New(Tmenu)
  683.         else
  684.           EdError(EdGetMessage(35));
  685.         with Tmenu^ do begin
  686.           XPosn := Xp;
  687.           YPosn := Yp;
  688.           XSize := Xs;
  689.           YSize := Ys;
  690.           MenuLev := Lev;
  691.           SubMax := Smax;
  692.           SubCur := 0;
  693.           SubOn := False;
  694.           if EdMemAvail(SubMax*SizeOf(SubMenuRecord), FreeListPerm) then
  695.             GetMem(SubMenus, SubMax*SizeOf(SubMenuRecord))
  696.           else
  697.             EdError(EdGetMessage(35));
  698.         end;
  699.       end;
  700.  
  701.       case Lev of
  702.         1 : RootMenu := Tmenu;
  703.  
  704.         2 : if EdPtrIsNil(RootMenu) then
  705.               EdError(EdGetMessage(106))
  706.             else
  707.               with RootMenu^ do begin
  708.                 Inc(SubCur);
  709.                 if SubCur > SubMax then
  710.                   EdError(EdGetMessage(107));
  711.                 SubMenus^[SubCur].SubMenu := Tmenu;
  712.               end;
  713.  
  714.         3 : if EdPtrIsNil(RootMenu) then
  715.               EdError(EdGetMessage(106))
  716.             else
  717.               with RootMenu^ do begin
  718.                 Smenu := RootMenu^.SubMenus^[RootMenu^.SubCur].SubMenu;
  719.                 if EdPtrIsNil(Smenu) then
  720.                   EdError(EdGetMessage(106))
  721.                 else
  722.                   with Smenu^ do begin
  723.                     Inc(SubCur);
  724.                     if SubCur > SubMax then
  725.                       EdError(EdGetMessage(107));
  726.                     SubMenus^[SubCur].SubMenu := Tmenu;
  727.                   end;
  728.               end;
  729.  
  730.       else
  731.         EdError(EdGetMessage(108));
  732.       end;
  733.  
  734.     end;                     {EdInitMenu}
  735.  
  736.     procedure EdInitItem(P : InitArrayPtr; var InitPos : Integer;
  737.                          var Sub : SubMenuRecord);
  738.       {-Initialize the parameters of one menu entry}
  739.     var
  740.       Cord, Dofs, Spec, Sofs : Byte;
  741.  
  742.     begin                    {Edinititem}
  743.  
  744.       {Get the next four bytes from the initialization data}
  745.       Cord := EdGetInitByte(P, InitPos);
  746.       Dofs := EdGetInitByte(P, InitPos);
  747.       Spec := EdGetInitByte(P, InitPos);
  748.       Sofs := EdGetInitByte(P, InitPos);
  749.  
  750.       {Store the record}
  751.       with Sub do begin
  752.         Soffset := Succ(Sofs); {String index where selection char is}
  753.         Doffset := Dofs;
  754.         StatVal := Spec;
  755.         Command := CommandType(Cord);
  756.         {Assume no deeper submenus}
  757.         EdSetPtrNil(SubMenu);
  758.         {Store pointer to string}
  759.         Prompt := Ptr(Seg(P^), Ofs(P^)+Pred(InitPos));
  760.         {Skip over string}
  761.         InitPos := InitPos+Succ(P^[InitPos]);
  762.       end;
  763.  
  764.     end;                     {Edinititem}
  765.  
  766.     procedure EdTraverseMenus(Menu : Menuptr);
  767.       {-Traverse the entire menu system, setting the current submenu to 1}
  768.     var
  769.       Sub : Byte;
  770.       S : Menuptr;
  771.  
  772.     begin                    {EdTraverseMenu}
  773.       with Menu^ do begin
  774.         SubCur := 1;
  775.         for Sub := 1 to SubMax do begin
  776.           S := SubMenus^[Sub].SubMenu;
  777.           if EdPtrNotNil(S) then
  778.             {Recursive call to traverse the next level}
  779.             EdTraverseMenus(S);
  780.         end;
  781.       end;
  782.     end;                     {EdTraverseMenu}
  783.  
  784.   begin                      {EdInitMenus}
  785.  
  786.     {No root menu exists initially}
  787.     EdSetPtrNil(RootMenu);
  788.  
  789.     {Initialize the menu descriptors for each menu level}
  790.     EdInitMenuDesc(MenuDesc);
  791.  
  792.     {Get a pointer to the embedded menu initialization data}
  793.     P := EdGetMenuInitPtr;
  794.     InitPos := 1;
  795.  
  796.     repeat
  797.       {Initialize a menu group}
  798.       EdInitMenu(P, InitPos, Smax, Tmenu);
  799.       if EdPtrNotNil(Tmenu) then
  800.         {Initialize the entries for the menu group}
  801.         for I := 1 to Smax do
  802.           EdInitItem(P, InitPos, Tmenu^.SubMenus^[I]);
  803.     until P^[InitPos] = $FF;
  804.  
  805.     {Set initial selections}
  806.     EdTraverseMenus(RootMenu);
  807.  
  808.     {No menu is currently displayed}
  809.     EdSetPtrNil(CurrMenu);
  810.     ExitMenu := True;
  811.  
  812.   end;                       {EdInitMenus}
  813.  
  814. begin
  815.   {Initialize menu system}
  816.   EdInitMenus;
  817. end.
  818.