home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 301_01 / menu.c < prev    next >
C/C++ Source or Header  |  1989-12-30  |  58KB  |  2,554 lines

  1. /*
  2.     HEADER:      CUG301;
  3.     TITLE:       Graphics pull down menu system;
  4.     DATE:        09/30/89;
  5.     DESCRIPTION: "C language calls can be used to easily define pull-down
  6.                       menus by using this menu system.  The routines currently
  7.                       only support graphics mode and not text mode.";
  8.     KEYWORDS:       user interface, graphics, quick prototype;
  9.     FILENAME:       MENU.C;
  10.     WARNINGS:       "The author claims copyrights and authorizes
  11.                       non-commercial use only.";
  12.     AUTHORS:       John Muczynski;
  13.     COMPILERS:   Turbo C version 2.0;
  14. */
  15. /*
  16.     menu.c
  17.  
  18.     Pull down (graphics) menus.
  19.  
  20.  
  21.  
  22.     (c) Copyright 1989 by John Muczynski. All Rights Reserved.
  23. */
  24.  
  25.  
  26. /*
  27.     bulletins
  28. jsm    09/01/89    creation
  29. jsm    09/01/89    need to work on 
  30.             -HORIZ/VERT
  31.             -keys
  32.             -longkeys
  33.             -macros
  34.             -saving screen position and shortname size
  35. jsm    09/03/89    finished debug
  36.     known problems:
  37.     1. If a menu is too big to fit on the screen, getmaxx and getmaxy 
  38.        don't seem to flag the problem.
  39.     2. If a menu is too big to fit on the screen, the turbo routines to
  40.        save and restore the screen data that is overwritten don't work
  41.        properly.  No data is restored.
  42.     3. Menu keys are not accepted in both upper and lower case (yet).
  43.     4. The macro editor is not complete.
  44.     5. The configuration of the database is not saved/restored to/from a
  45.        file yet.
  46.  
  47. jsm    09/04/89  started supporting upper/lower case conversion.
  48.           The cursor is now passed to both the hotkeys as well
  49.           as the menu functions.            
  50.           known 09/03/89 problems 1 and 2 are fixed.
  51.           Adding utilities submenu.          
  52. jsm    09/05/89  lower case works
  53.           getmaxx and y are used in padtext now
  54.           cursor now skips invisible menu entries
  55.           menus now re-draw when using hotkeys to move a menu
  56.           rootmenu is now in upper left corner all the way (0,0)
  57.     1      Utilities work okay except meta-hotkey.
  58.           known 09/03/89 problems 3 4 and 5 are fixed.
  59.     2      not all of configuration is saved yet -- problem finding a
  60.           representation for the menus -- don't want to use C.
  61. jsm    09/05/89  Fixed problems 1 from 09/05/89
  62.     1      note: horizontal menus's that don't fit can be changed
  63.           into vertical menus.
  64.     2      need to complete and debug configuration read/write.
  65.           hot key has problems.
  66.  
  67. jsm    09/08/89  fixing hot key.
  68.           fixing macro read/write from config file.
  69.           Now config saves everything except the information contained
  70.           in the menu structures.
  71.     3      Want to be able to change the names of keys and functions.
  72.  
  73.  
  74.  
  75. FUTURE EXPANSION:
  76. JSM      09/29/89 -Need some facility to auto-run some macro when the program
  77.                    is doing initialization.
  78.                   -Need to auto-load the MENU.TMP file.
  79.                   -Need to make the words inside a menu both horizontal and
  80.                    vertical, just as the menu itself can be built horizontal
  81.                    or vertical.
  82.                   -Need to allow the menus to be called up from either text
  83.                    mode or graphics mode.
  84.                   -Need to add 'backspace' capability to the macro entry
  85.                    routine.
  86.                   -Need to add documentation.
  87.                   -Need to make a environment parameter for the name
  88.                    of the 'MENU.TMP' file (it's full path name).
  89.                   -Need to expand the config. file to include the data which
  90.                    is saved in the menu structures.
  91.                   -Mouse support would be nice...
  92. */
  93.  
  94. /* define DEBUG */
  95. #define debug1 0
  96. #define debug2 0
  97. #define debug3 0
  98.  
  99. #include <stdlib.h>
  100. #include <stdio.h>
  101. #include <time.h>
  102. #include <ctype.h>
  103. #include <string.h>
  104.  
  105. #include <bios.h>
  106. #include <graphics.h>
  107. #include <conio.h>
  108.  
  109.  
  110. static int accumx, accumy;
  111.  
  112. typedef void fn();
  113.  
  114.  
  115.  
  116. void my_wait_key(){};              /* default for above */
  117. fn *the_wait_key = my_wait_key;
  118.  
  119. /* define how to wait for keys */
  120. void wait_key(fn funct)
  121. {
  122.   the_wait_key = funct;
  123. };
  124.  
  125.  
  126.  
  127. /* function to get a key from the user
  128.     returns a keyboard value.
  129. */
  130. long int get_key()
  131. {
  132.   int ext;
  133.   int key;
  134.   long int lkey;
  135.  
  136.   while (! bioskey(1)) {
  137.     the_wait_key();        /* do what the user wants */
  138.   };
  139.  
  140.  
  141.   if (bioskey(1)) {
  142.     key = bioskey(0);
  143.     ext = bioskey(2);
  144.  
  145.     if (key&0xFF) {
  146.       lkey = key&0xFF;
  147.     }else{
  148.       lkey=0l;
  149.       if (ext&0x03) lkey = lkey ^ 0x10000l;
  150.  
  151.       lkey = lkey + key;
  152.     };
  153.   };
  154.  
  155.   return( 0x10000l + (0x1FFFFl & lkey)  );
  156.  
  157. };
  158.  
  159.  
  160. struct mac {
  161.     long int fkey;
  162.     struct mac *next;
  163.     struct mac *prev;
  164. };
  165.  
  166.  
  167.  
  168. #define LASTKEY  330
  169. int lastkey = 273;
  170.   long int keys[LASTKEY+1] = {0};    /* keyboard values for each key */
  171.   char *keynames[LASTKEY+1] = {0};    /* names for each key */
  172.   struct mac *mac[LASTKEY+1] = {0};    /* macros for each key */
  173.  
  174.  
  175.  
  176. /* yes, this table was generated by a program. */
  177. void init_keys()
  178. {
  179.   keys[0] = 0x10001l;
  180.   keynames[0] = "[CTRL-A]";
  181.   keys[1] = 0x10002l;
  182.   keynames[1] = "[CTRL-B]";
  183.   keys[2] = 0x10004l;
  184.   keynames[2] = "[CTRL-D]";
  185.   keys[3] = 0x10005l;
  186.   keynames[3] = "[CTRL-E]";
  187.   keys[4] = 0x10006l;
  188.   keynames[4] = "[CTRL-F]";
  189.   keys[5] = 0x10007l;
  190.   keynames[5] = "[CTRL-G]";
  191.   keys[6] = 0x10008l;
  192.   keynames[6] = "[BKSP]";
  193.   keys[7] = 0x10009l;
  194.   keynames[7] = "[TAB]";
  195.   keys[8] = 0x1000Al;
  196.   keynames[8] = "[CTRL-J]";
  197.   keys[9] = 0x1000Bl;
  198.   keynames[9] = "[CTRL-K]";
  199.   keys[10] = 0x1000Cl;
  200.   keynames[10] = "[CTRL-L]";
  201.   keys[11] = 0x1000Dl;
  202.   keynames[11] = "[ENTER]";
  203.   keys[12] = 0x1000El;
  204.   keynames[12] = "[CTRL-N]";
  205.   keys[13] = 0x1000Fl;
  206.   keynames[13] = "[CTRL-O]";
  207.   keys[14] = 0x10010l;
  208.   keynames[14] = "[CTRL-P]";
  209.   keys[15] = 0x10011l;
  210.   keynames[15] = "[CTRL-Q]";
  211.   keys[16] = 0x10012l;
  212.   keynames[16] = "[CTRL-R]";
  213.   keys[17] = 0x10013l;
  214.   keynames[17] = "[CTRL-S]";
  215.   keys[18] = 0x10014l;
  216.   keynames[18] = "[CTRL-T]";
  217.   keys[19] = 0x10015l;
  218.   keynames[19] = "[CTRL-U]";
  219.   keys[20] = 0x10016l;
  220.   keynames[20] = "[CTRL-V]";
  221.   keys[21] = 0x10017l;
  222.   keynames[21] = "[CTRL-W]";
  223.   keys[22] = 0x10018l;
  224.   keynames[22] = "[CTRL-X]";
  225.   keys[23] = 0x10019l;
  226.   keynames[23] = "[CTRL-Y]";
  227.   keys[24] = 0x1001Al;
  228.   keynames[24] = "[CTRL-Z]";
  229.   keys[25] = 0x1001Bl;
  230.   keynames[25] = "[ESCAPE]";
  231.   keys[26] = 0x1001Cl;
  232.   keynames[26] = "[CTRL-\]";
  233.   keys[27] = 0x1001Dl;
  234.   keynames[27] = "[CTRL-]]";
  235.   keys[28] = 0x1001El;
  236.   keynames[28] = "[CTRL-^]";
  237.   keys[29] = 0x1001Fl;
  238.   keynames[29] = "[CTRL-DASH]";
  239.   keys[30] = 0x10020l;
  240.   keynames[30] = "[SPACE]";
  241.   keys[31] = 0x10021l;
  242.   keynames[31] = "[!]";
  243.   keys[32] = 0x10022l;
  244.   keynames[32] = "[\"]";
  245.   keys[33] = 0x10023l;
  246.   keynames[33] = "[#]";
  247.   keys[34] = 0x10024l;
  248.   keynames[34] = "[$]";
  249.   keys[35] = 0x10025l;
  250.   keynames[35] = "[%]";
  251.   keys[36] = 0x10026l;
  252.   keynames[36] = "[&]";
  253.   keys[37] = 0x10027l;
  254.   keynames[37] = "[']";
  255.   keys[38] = 0x10028l;
  256.   keynames[38] = "[(]";
  257.   keys[39] = 0x10029l;
  258.   keynames[39] = "[)]";
  259.   keys[40] = 0x1002Al;
  260.   keynames[40] = "[*]";
  261.   keys[41] = 0x1002Bl;
  262.   keynames[41] = "[+]";
  263.   keys[42] = 0x1002Cl;
  264.   keynames[42] = "[,]";
  265.   keys[43] = 0x1002Dl;
  266.   keynames[43] = "[-]";
  267.   keys[44] = 0x1002El;
  268.   keynames[44] = "[.]";
  269.   keys[45] = 0x1002Fl;
  270.   keynames[45] = "[/]";
  271.   keys[46] = 0x10030l;
  272.   keynames[46] = "[0]";
  273.   keys[47] = 0x10031l;
  274.   keynames[47] = "[1]";
  275.   keys[48] = 0x10032l;
  276.   keynames[48] = "[2]";
  277.   keys[49] = 0x10033l;
  278.   keynames[49] = "[3]";
  279.   keys[50] = 0x10034l;
  280.   keynames[50] = "[4]";
  281.   keys[51] = 0x10035l;
  282.   keynames[51] = "[5]";
  283.   keys[52] = 0x10036l;
  284.   keynames[52] = "[6]";
  285.   keys[53] = 0x10037l;
  286.   keynames[53] = "[7]";
  287.   keys[54] = 0x10038l;
  288.   keynames[54] = "[8]";
  289.   keys[55] = 0x10039l;
  290.   keynames[55] = "[9]";
  291.   keys[56] = 0x1003Al;
  292.   keynames[56] = "[:]";
  293.   keys[57] = 0x1003Bl;
  294.   keynames[57] = "[;]";
  295.   keys[58] = 0x1003Cl;
  296.   keynames[58] = "[<]";
  297.   keys[59] = 0x1003Dl;
  298.   keynames[59] = "[=]";
  299.   keys[60] = 0x1003El;
  300.   keynames[60] = "[>]";
  301.   keys[61] = 0x1003Fl;
  302.   keynames[61] = "[?]";
  303.   keys[62] = 0x10040l;
  304.   keynames[62] = "[@]";
  305.   keys[63] = 0x10041l;
  306.   keynames[63] = "[A]";
  307.   keys[64] = 0x10042l;
  308.   keynames[64] = "[B]";
  309.   keys[65] = 0x10043l;
  310.   keynames[65] = "[C]";
  311.   keys[66] = 0x10044l;
  312.   keynames[66] = "[D]";
  313.   keys[67] = 0x10045l;
  314.   keynames[67] = "[E]";
  315.   keys[68] = 0x10046l;
  316.   keynames[68] = "[F]";
  317.   keys[69] = 0x10047l;
  318.   keynames[69] = "[G]";
  319.   keys[70] = 0x10048l;
  320.   keynames[70] = "[H]";
  321.   keys[71] = 0x10049l;
  322.   keynames[71] = "[I]";
  323.   keys[72] = 0x1004Al;
  324.   keynames[72] = "[J]";
  325.   keys[73] = 0x1004Bl;
  326.   keynames[73] = "[K]";
  327.   keys[74] = 0x1004Cl;
  328.   keynames[74] = "[L]";
  329.   keys[75] = 0x1004Dl;
  330.   keynames[75] = "[M]";
  331.   keys[76] = 0x1004El;
  332.   keynames[76] = "[N]";
  333.   keys[77] = 0x1004Fl;
  334.   keynames[77] = "[O]";
  335.   keys[78] = 0x10050l;
  336.   keynames[78] = "[P]";
  337.   keys[79] = 0x10051l;
  338.   keynames[79] = "[Q]";
  339.   keys[80] = 0x10052l;
  340.   keynames[80] = "[R]";
  341.   keys[81] = 0x10053l;
  342.   keynames[81] = "[S]";
  343.   keys[82] = 0x10054l;
  344.   keynames[82] = "[T]";
  345.   keys[83] = 0x10055l;
  346.   keynames[83] = "[U]";
  347.   keys[84] = 0x10056l;
  348.   keynames[84] = "[V]";
  349.   keys[85] = 0x10057l;
  350.   keynames[85] = "[W]";
  351.   keys[86] = 0x10058l;
  352.   keynames[86] = "[X]";
  353.   keys[87] = 0x10059l;
  354.   keynames[87] = "[Y]";
  355.   keys[88] = 0x1005Al;
  356.   keynames[88] = "[Z]";
  357.   keys[89] = 0x1005Bl;
  358.   keynames[89] = "[[]";
  359.   keys[90] = 0x1005Cl;
  360.   keynames[90] = "[\]";
  361.   keys[91] = 0x1005Dl;
  362.   keynames[91] = "[]]";
  363.   keys[92] = 0x1005El;
  364.   keynames[92] = "[^]";
  365.   keys[93] = 0x1005Fl;
  366.   keynames[93] = "[_]";
  367.   keys[94] = 0x10060l;
  368.   keynames[94] = "[`]";
  369.   keys[95] = 0x10061l;
  370.   keynames[95] = "[a]";
  371.   keys[96] = 0x10062l;
  372.   keynames[96] = "[b]";
  373.   keys[97] = 0x10063l;
  374.   keynames[97] = "[c]";
  375.   keys[98] = 0x10064l;
  376.   keynames[98] = "[d]";
  377.   keys[99] = 0x10065l;
  378.   keynames[99] = "[e]";
  379.   keys[100] = 0x10066l;
  380.   keynames[100] = "[f]";
  381.   keys[101] = 0x10067l;
  382.   keynames[101] = "[g]";
  383.   keys[102] = 0x10068l;
  384.   keynames[102] = "[h]";
  385.   keys[103] = 0x10069l;
  386.   keynames[103] = "[i]";
  387.   keys[104] = 0x1006Al;
  388.   keynames[104] = "[j]";
  389.   keys[105] = 0x1006Bl;
  390.   keynames[105] = "[k]";
  391.   keys[106] = 0x1006Cl;
  392.   keynames[106] = "[l]";
  393.   keys[107] = 0x1006Dl;
  394.   keynames[107] = "[m]";
  395.   keys[108] = 0x1006El;
  396.   keynames[108] = "[n]";
  397.   keys[109] = 0x1006Fl;
  398.   keynames[109] = "[o]";
  399.   keys[110] = 0x10070l;
  400.   keynames[110] = "[p]";
  401.   keys[111] = 0x10071l;
  402.   keynames[111] = "[q]";
  403.   keys[112] = 0x10072l;
  404.   keynames[112] = "[r]";
  405.   keys[113] = 0x10073l;
  406.   keynames[113] = "[s]";
  407.   keys[114] = 0x10074l;
  408.   keynames[114] = "[t]";
  409.   keys[115] = 0x10075l;
  410.   keynames[115] = "[u]";
  411.   keys[116] = 0x10076l;
  412.   keynames[116] = "[v]";
  413.   keys[117] = 0x10077l;
  414.   keynames[117] = "[w]";
  415.   keys[118] = 0x10078l;
  416.   keynames[118] = "[x]";
  417.   keys[119] = 0x10079l;
  418.   keynames[119] = "[y]";
  419.   keys[120] = 0x1007Al;
  420.   keynames[120] = "[z]";
  421.   keys[121] = 0x1007Bl;
  422.   keynames[121] = "[{]";
  423.   keys[122] = 0x1007Cl;
  424.   keynames[122] = "[|]";
  425.   keys[123] = 0x1007Dl;
  426.   keynames[123] = "[}]";
  427.   keys[124] = 0x1007El;
  428.   keynames[124] = "[~]";
  429.   keys[125] = 0x1007Fl;
  430.   keynames[125] = "[CTRL-BACKSPACE]";
  431.   keys[126] = 0x100D2l;
  432.   keynames[126] = "[WHAT]";
  433.   keys[127] = 0x10300l;
  434.   keynames[127] = "[CTRL-2]";
  435.   keys[128] = 0x11000l;
  436.   keynames[128] = "[ALT-Q]";
  437.   keys[129] = 0x11100l;
  438.   keynames[129] = "[ALT-W]";
  439.   keys[130] = 0x11200l;
  440.   keynames[130] = "[ALT-E]";
  441.   keys[131] = 0x11300l;
  442.   keynames[131] = "[ALT-R]";
  443.   keys[132] = 0x11400l;
  444.   keynames[132] = "[ALT-T]";
  445.   keys[133] = 0x11500l;
  446.   keynames[133] = "[ALT-Y]";
  447.   keys[134] = 0x11600l;
  448.   keynames[134] = "[ALT-U]";
  449.   keys[135] = 0x11700l;
  450.   keynames[135] = "[ALT-I]";
  451.   keys[136] = 0x11800l;
  452.   keynames[136] = "[ALT-O]";
  453.   keys[137] = 0x11900l;
  454.   keynames[137] = "[ALT-P]";
  455.   keys[138] = 0x11E00l;
  456.   keynames[138] = "[ALT-A]";
  457.   keys[139] = 0x11F00l;
  458.   keynames[139] = "[ALT-S]";
  459.   keys[140] = 0x12000l;
  460.   keynames[140] = "[ALT-D]";
  461.   keys[141] = 0x12100l;
  462.   keynames[141] = "[ALT-E]";
  463.   keys[142] = 0x12200l;
  464.   keynames[142] = "[ALT-G]";
  465.   keys[143] = 0x12300l;
  466.   keynames[143] = "[ALT-H]";
  467.   keys[144] = 0x12400l;
  468.   keynames[144] = "[ALT-J]";
  469.   keys[145] = 0x12500l;
  470.   keynames[145] = "[ALT-K]";
  471.   keys[146] = 0x12600l;
  472.   keynames[146] = "[ALT-L]";
  473.   keys[147] = 0x12C00l;
  474.   keynames[147] = "[ALT-Z]";
  475.   keys[148] = 0x12D00l;
  476.   keynames[148] = "[ALT-X]";
  477.   keys[149] = 0x12E00l;
  478.   keynames[149] = "[ALT-C]";
  479.   keys[150] = 0x12F00l;
  480.   keynames[150] = "[ALT-V]";
  481.   keys[151] = 0x13000l;
  482.   keynames[151] = "[ALT-B]";
  483.   keys[152] = 0x13100l;
  484.   keynames[152] = "[ALT-N]";
  485.   keys[153] = 0x13200l;
  486.   keynames[153] = "[ALT-M]";
  487.   keys[154] = 0x13B00l;
  488.   keynames[154] = "[F1]";
  489.   keys[155] = 0x13C00l;
  490.   keynames[155] = "[F2]";
  491.   keys[156] = 0x13D00l;
  492.   keynames[156] = "[F3]";
  493.   keys[157] = 0x13E00l;
  494.   keynames[157] = "[F4]";
  495.   keys[158] = 0x13F00l;
  496.   keynames[158] = "[F5]";
  497.   keys[159] = 0x14000l;
  498.   keynames[159] = "[F6]";
  499.   keys[160] = 0x14100l;
  500.   keynames[160] = "[F7]";
  501.   keys[161] = 0x14200l;
  502.   keynames[161] = "[F8]";
  503.   keys[162] = 0x14300l;
  504.   keynames[162] = "[F9]";
  505.   keys[163] = 0x14400l;
  506.   keynames[163] = "[F10]";
  507.   keys[164] = 0x14700l;
  508.   keynames[164] = "[HOME]";
  509.   keys[165] = 0x14800l;
  510.   keynames[165] = "[ARROW-UP]";
  511.   keys[166] = 0x14900l;
  512.   keynames[166] = "[PAGE-UP]";
  513.   keys[167] = 0x14B00l;
  514.   keynames[167] = "[ARROW-LEFT]";
  515.   keys[168] = 0x14D00l;
  516.   keynames[168] = "[ARROW-RIGHT]";
  517.   keys[169] = 0x14F00l;
  518.   keynames[169] = "[END]";
  519.   keys[170] = 0x15000l;
  520.   keynames[170] = "[ARROW-DOWN]";
  521.   keys[171] = 0x15100l;
  522.   keynames[171] = "[PAGE-DOWN]";
  523.   keys[172] = 0x15200l;
  524.   keynames[172] = "[INSERT]";
  525.   keys[173] = 0x15300l;
  526.   keynames[173] = "[DELETE]";
  527.   keys[174] = 0x15E00l;
  528.   keynames[174] = "[CTRL-F1]";
  529.   keys[175] = 0x15F00l;
  530.   keynames[175] = "[CTRL-F2]";
  531.   keys[176] = 0x16000l;
  532.   keynames[176] = "[CTRL-F3]";
  533.   keys[177] = 0x16100l;
  534.   keynames[177] = "[CTRL-F4]";
  535.   keys[178] = 0x16200l;
  536.   keynames[178] = "[CTRL-F5]";
  537.   keys[179] = 0x16300l;
  538.   keynames[179] = "[CTRL-F6]";
  539.   keys[180] = 0x16400l;
  540.   keynames[180] = "[CTRL-F7]";
  541.   keys[181] = 0x16500l;
  542.   keynames[181] = "[CTRL-F8]";
  543.   keys[182] = 0x16600l;
  544.   keynames[182] = "[CTRL-F9]";
  545.   keys[183] = 0x16700l;
  546.   keynames[183] = "[CTRL-F10]";
  547.   keys[184] = 0x16800l;
  548.   keynames[184] = "[ALT-F1]";
  549.   keys[185] = 0x16900l;
  550.   keynames[185] = "[ALT-F2]";
  551.   keys[186] = 0x16A00l;
  552.   keynames[186] = "[ALT-F3]";
  553.   keys[187] = 0x16B00l;
  554.   keynames[187] = "[ALT-F4]";
  555.   keys[188] = 0x16C00l;
  556.   keynames[188] = "[ALT-F5]";
  557.   keys[189] = 0x16D00l;
  558.   keynames[189] = "[ALT-F6]";
  559.   keys[190] = 0x16E00l;
  560.   keynames[190] = "[ALT-F7]";
  561.   keys[191] = 0x16F00l;
  562.   keynames[191] = "[ALT-F8]";
  563.   keys[192] = 0x17000l;
  564.   keynames[192] = "[ALT-F9]";
  565.   keys[193] = 0x17100l;
  566.   keynames[193] = "[ALT-F10]";
  567.   keys[194] = 0x17300l;
  568.   keynames[194] = "[CTRL-ARROW-LEFT]";
  569.   keys[195] = 0x17400l;
  570.   keynames[195] = "[CTRL-ARROW-RIGHT]";
  571.   keys[196] = 0x17500l;
  572.   keynames[196] = "[CTRL-END]";
  573.   keys[197] = 0x17600l;
  574.   keynames[197] = "[CTRL-PAGE-DOWN]";
  575.   keys[198] = 0x17700l;
  576.   keynames[198] = "[CTRL-HOME]";
  577.   keys[199] = 0x17800l;
  578.   keynames[199] = "[ALT-1]";
  579.   keys[200] = 0x17900l;
  580.   keynames[200] = "[ALT-2]";
  581.   keys[201] = 0x17A00l;
  582.   keynames[201] = "[ALT-3]";
  583.   keys[202] = 0x17B00l;
  584.   keynames[202] = "[ALT-4]";
  585.   keys[203] = 0x17C00l;
  586.   keynames[203] = "[ALT-5]";
  587.   keys[204] = 0x17D00l;
  588.   keynames[204] = "[ALT-6]";
  589.   keys[205] = 0x17E00l;
  590.   keynames[205] = "[ALT-7]";
  591.   keys[206] = 0x17F00l;
  592.   keynames[206] = "[ALT-8]";
  593.   keys[207] = 0x18000l;
  594.   keynames[207] = "[SHIFT-ALT-9]";
  595.   keys[208] = 0x18100l;
  596.   keynames[208] = "[SHIFT-ALT-0]";
  597.   keys[209] = 0x18200l;
  598.   keynames[209] = "[ALT-UNDERSCORE]";
  599.   keys[210] = 0x18300l;
  600.   keynames[210] = "[ALT-PLUS]";
  601.   keys[211] = 0x20300l;
  602.   keynames[211] = "[CTRL-@]";
  603.   keys[212] = 0x20F00l;
  604.   keynames[212] = "[BACKTAB]";
  605.   keys[213] = 0x21000l;
  606.   keynames[213] = "[SHIFT-ALT-Q]";
  607.   keys[214] = 0x21100l;
  608.   keynames[214] = "[SHIFT-ALT-W]";
  609.   keys[215] = 0x21200l;
  610.   keynames[215] = "[SHIFT-ALT-E]";
  611.   keys[216] = 0x21300l;
  612.   keynames[216] = "[SHIFT-ALT-R]";
  613.   keys[217] = 0x21400l;
  614.   keynames[217] = "[SHIFT-ALT-T]";
  615.   keys[218] = 0x21500l;
  616.   keynames[218] = "[SHIFT-ALT-Y]";
  617.   keys[219] = 0x21600l;
  618.   keynames[219] = "[SHIFT-ALT-U]";
  619.   keys[220] = 0x21700l;
  620.   keynames[220] = "[SHIFT-ALT-I]";
  621.   keys[221] = 0x21800l;
  622.   keynames[221] = "[SHIFT-ALT-O]";
  623.   keys[222] = 0x21900l;
  624.   keynames[222] = "[SHIFT-ALT-P]";
  625.   keys[223] = 0x21E00l;
  626.   keynames[223] = "[SHIFT-ALT-A]";
  627.   keys[224] = 0x21F00l;
  628.   keynames[224] = "[SHIFT-ALT-S]";
  629.   keys[225] = 0x22000l;
  630.   keynames[225] = "[SHIFT-ALT-D]";
  631.   keys[226] = 0x22100l;
  632.   keynames[226] = "[SHIFT-ALT-F]";
  633.   keys[227] = 0x22200l;
  634.   keynames[227] = "[SHIFT-ALT-G]";
  635.   keys[228] = 0x22300l;
  636.   keynames[228] = "[SHIFT-ALT-H]";
  637.   keys[229] = 0x22400l;
  638.   keynames[229] = "[SHIFT-ALT-J]";
  639.   keys[230] = 0x22500l;
  640.   keynames[230] = "[SHIFT-ALT-K]";
  641.   keys[231] = 0x22600l;
  642.   keynames[231] = "[SHIFT-ALT-L]";
  643.   keys[232] = 0x22C00l;
  644.   keynames[232] = "[SHIFT-ALT-Z]";
  645.   keys[233] = 0x22D00l;
  646.   keynames[233] = "[SHIFT-ALT-X]";
  647.   keys[234] = 0x22E00l;
  648.   keynames[234] = "[SHIFT-ALT-C]";
  649.   keys[235] = 0x22F00l;
  650.   keynames[235] = "[SHIFT-ALT-V]";
  651.   keys[236] = 0x23000l;
  652.   keynames[236] = "[SHIFT-ALT-B]";
  653.   keys[237] = 0x23100l;
  654.   keynames[237] = "[SHIFT-ALT-N]";
  655.   keys[238] = 0x23200l;
  656.   keynames[238] = "[SHIFT-ALT-M]";
  657.   keys[239] = 0x24700l;
  658.   keynames[239] = "[SHIFT-HOME]";
  659.   keys[240] = 0x24800l;
  660.   keynames[240] = "[SHIFT-ARROW-UP]";
  661.   keys[241] = 0x24900l;
  662.   keynames[241] = "[SHIFT-PAGE-UP]";
  663.   keys[242] = 0x24B00l;
  664.   keynames[242] = "[SHIFT-ARROW-LEFT]";
  665.   keys[243] = 0x24D00l;
  666.   keynames[243] = "[SHIFT-ARROW-RIGHT]";
  667.   keys[244] = 0x24F00l;
  668.   keynames[244] = "[SHIFT-END]";
  669.   keys[245] = 0x25000l;
  670.   keynames[245] = "[SHIFT-ARROW-DOWN]";
  671.   keys[246] = 0x25100l;
  672.   keynames[246] = "[SHIFT-PAGE-DOWN]";
  673.   keys[247] = 0x25200l;
  674.   keynames[247] = "[SHIFT-INSERT]";
  675.   keys[248] = 0x25300l;
  676.   keynames[248] = "[SHIFT-DELETE]";
  677.   keys[249] = 0x25400l;
  678.   keynames[249] = "[SHIFT-F1]";
  679.   keys[250] = 0x25500l;
  680.   keynames[250] = "[SHIFT-F2]";
  681.   keys[251] = 0x25600l;
  682.   keynames[251] = "[SHIFT-F3]";
  683.   keys[252] = 0x25700l;
  684.   keynames[252] = "[SHIFT-F4]";
  685.   keys[253] = 0x25800l;
  686.   keynames[253] = "[SHIFT-F5]";
  687.   keys[254] = 0x25900l;
  688.   keynames[254] = "[SHIFT-F6]";
  689.   keys[255] = 0x25A00l;
  690.   keynames[255] = "[SHIFT-F7]";
  691.   keys[256] = 0x25B00l;
  692.   keynames[256] = "[SHIFT-F8]";
  693.   keys[257] = 0x25C00l;
  694.   keynames[257] = "[SHIFT-F9]";
  695.   keys[258] = 0x25D00l;
  696.   keynames[258] = "[SHIFT-F10]";
  697.   keys[259] = 0x27800l;
  698.   keynames[259] = "[SHIFT-ALT-1]";
  699.   keys[260] = 0x27900l;
  700.   keynames[260] = "[SHIFT-ALT-2]";
  701.   keys[261] = 0x27A00l;
  702.   keynames[261] = "[SHIFT-ALT-3]";
  703.   keys[262] = 0x27B00l;
  704.   keynames[262] = "[SHIFT-ALT-4]";
  705.   keys[263] = 0x27C00l;
  706.   keynames[263] = "[SHIFT-ALT-5]";
  707.   keys[264] = 0x27D00l;
  708.   keynames[264] = "[SHIFT-ALT-6]";
  709.   keys[265] = 0x27E00l;
  710.   keynames[265] = "[SHIFT-ALT-7]";
  711.   keys[266] = 0x27F00l;
  712.   keynames[266] = "[SHIFT-ALT-8]";
  713.  
  714.   keys[267] = 0x28000l;
  715.   keynames[267] = "[ALT-9]";
  716.   keys[268] = 0x28100l;
  717.   keynames[268] = "[ALT-0]";
  718.   keys[269] = 0x28200l;
  719.   keynames[269] = "[ALT-MINUS]";
  720.   keys[270] = 0x28300l;
  721.   keynames[270] = "[ALT-EQUAL]";
  722.   keys[271] = 0x28400l;
  723.   keynames[271] = "[CTRL-PAGE-UP]";
  724.  
  725.  
  726. };
  727.  
  728. /* BOXTEXT OFFSETS */
  729. #define BOX_X 3+1
  730. #define BOX_Y 3+1
  731.  
  732. /* HOW BIG OF A BOX DOES BOXTEXT NEED TO MAKE ? */
  733. #define boxsizex(data) textwidth(data)+BOX_X+BOX_X
  734. #define boxsizey(data) textheight(data)+BOX_Y+BOX_Y
  735.  
  736.  
  737. /* routine to print a text in a box
  738.    The text will have BOX_X-1 pixels between it and the horiz. walls.
  739.    The text will have BOX_Y-1 pixels between it and the vert. walls.
  740.    The text will be white pixels on a black background.
  741. */
  742. void boxtext(int x, int y, char *data)
  743.  
  744. {
  745.   int sx, sy;
  746.  
  747.   sx = boxsizex(data);
  748.   sy = boxsizey(data);
  749.  
  750.   /* clear area for text */
  751.   setfillstyle(0,0); 
  752.   bar(x,     y,
  753.       x+sx,  y+sy);
  754.  
  755.   /* put a box at edge of cleared area */
  756.   setcolor(15);
  757.   rectangle(x,     y,
  758.             x+sx,  y+sy);
  759.  
  760.   outtextxy(x+BOX_X,y+BOX_Y,data);
  761. };
  762.  
  763.  
  764.  
  765. /* routine to do a function for each line in a string
  766.    the lines are delimeted by '\n'
  767.  
  768.    this fn is not used yet.
  769. */
  770. void doeach_line(int x, int y, char *data, fn funct)
  771. {
  772.   char part[180];
  773.   int i =0;
  774.   int tot;
  775.  
  776.   tot = strlen(data);
  777.   accumx=0;
  778.   accumy=0;
  779.  
  780. loop:
  781.   while (data[i] >=' ') part[i] = data[i++];
  782.   part[i]='\0';
  783.  
  784.   funct(x,y,part);
  785.   if (i<=tot) goto loop;
  786.  
  787. };
  788.  
  789.  
  790. struct submenu {
  791.     /* how the user describes this submenu entry */
  792.     unsigned char direction;/* HORIZONTAL, VERTICAL, INVISIBLE */
  793.     long int choicekey;    /* simple key to activate this submenu */
  794.     int lastchoice;        /* offset of last submenu of this menu that was used */
  795.     char *shortname;    /* name of this menu/function */
  796.     char *longname;        /* title line for submenu (or blank or zero) */
  797.     fn *funct;
  798.         int style;        /* background style */
  799.  
  800.     /* relationship to other submenu entries */
  801.     struct submenu *next;    /* right pointer */
  802.     struct submenu *prev;    /* left pointer */
  803.     struct submenu *sub;    /* down pointer */
  804.     struct submenu *esc;    /* up pointer */
  805.  
  806.     /* screen stuff */
  807.     int startx, starty;    /* where shortname starts at (on the screen) */
  808.     int belowx, belowy;    /* where longname would be put for submenu */
  809.     int sizex, sizey;    /* graphics size of shortname */
  810. };
  811.  
  812.  
  813. extern long int the_key=0;        /* function key value */
  814. long int keystack[900];
  815. extern int keys_ptr=0;
  816.  
  817.  
  818.  
  819. void undo_macro(struct submenu *one);
  820. void mk_macro();
  821.  
  822. void savescr();
  823. void restorescr();
  824. int indexof(long int lkey);
  825. void get_stack_key();
  826. void doeach_entry(struct submenu *it, fn funct);
  827. void def_submenu(char choice, char *shortname, char *longname);
  828. void endef_submenu(char *matchshort); /* repeat shortname to match & debug */
  829. void def_entry(char choice, char *shortname, fn funct );
  830. void menu_fn(fn funct );
  831. void menu_horizontal();
  832. void menu_invisible();
  833.  
  834.  
  835. void nofn() {};        /* default function does nothing */
  836.  
  837. #define MAXKEYS 500
  838. #define NUM_MYKEYS    8
  839. char *fkeynames[MAXKEYS+NUM_MYKEYS+2] = {0};
  840. fn  *hotkeyfn[MAXKEYS+NUM_MYKEYS+2] = {nofn};
  841. int enable_hotkeys = 1;
  842.  
  843. void prep_submenu(struct submenu *it);
  844. void dump_submenu(int x, int y, struct submenu *it);
  845. int key_submenu(struct submenu *it);
  846. void update_submenu(struct submenu *it);
  847.  
  848. int find_fnindex(fn *thisfn);
  849. void padtext(int x, int y, char *data, int style);
  850.  
  851.  
  852.  
  853.  
  854. #define KEY_RIGHT     MAXKEYS+1
  855. #define KEY_LEFT      MAXKEYS+2
  856. #define KEY_SUB       MAXKEYS+3
  857. #define KEY_ESC       MAXKEYS+4
  858. #define KEY_TOTAL_ESC MAXKEYS+5
  859. #define KEY_DOWN      MAXKEYS+6
  860. #define KEY_UP        MAXKEYS+7
  861.  
  862.  
  863.  
  864. /* This routine allows the user to define a function-key.
  865.    The keynum is "made up" by the user.
  866.    It is a value between 1 and MAXKEYS and is used to match a keyboard entry
  867.    to the key.
  868.  
  869.    The keyboard entry assigned to this function key is passed as an ASCII name.
  870.    The name for this keyboard entry is passed as keyname.  
  871.    Any value may be entered and the fkey may be
  872.    re-defined later and saved in a config. file.
  873.  
  874.    From now on, whenever keyname is typed on the keyboard, fkey will be 
  875.    returned as a value.  The name of fkey is fkeyname.
  876. */ 
  877. int def_fkey(int fkey, char *keyname, char *fkeyname);
  878. void user_menus();    /* this is defined by the user */
  879. void menu_run();        /* how to run the menu system */
  880.  
  881.  
  882. void read_config();
  883. void write_config();
  884.  
  885.  
  886. long int lkeyof(char ch);
  887.  
  888.  
  889.  
  890.  
  891. void init_fkeys()
  892. {
  893. def_fkey(KEY_RIGHT,     "[ARROW-RIGHT]",   "<KEY-RIGHT>"   );
  894. def_fkey(KEY_LEFT,      "[ARROW-LEFT]",    "<KEY-LEFT>"    );
  895. def_fkey(KEY_SUB,       "[ENTER]",         "<KEY-SUB>"     );
  896. def_fkey(KEY_ESC,       "[ESCAPE]",        "<KEY-ESC>"     );
  897. def_fkey(KEY_TOTAL_ESC, "[ALT-X]",         "<KEY-TOTAL-ESC>" );
  898. def_fkey(KEY_DOWN,      "[ARROW-DOWN]",    "<KEY-DOWN>"    );
  899. def_fkey(KEY_UP,        "[ARROW-UP]",      "<KEY-UP>"      );
  900. };
  901.  
  902.  
  903.  
  904.  
  905.  
  906. /* define a user defined key as being a 'hot' key.
  907.    Whenever the key is encountered by the decoding routine, the
  908.    given function will be executed.
  909. */
  910. void hot_key(int keynum, fn funct)
  911. {
  912.   if( (keynum>0) && (keynum <= MAXKEYS) ){
  913.     hotkeyfn[keynum] = funct;
  914.   };
  915. };
  916.  
  917.  
  918.  
  919.  
  920.  
  921. #define VERTICAL 1    /* default is vertical (after first level or horiz.) */
  922. #define HORIZONTAL 2
  923. #define INVISIBLE 3    /* the root and the subroots are place holders */
  924.  
  925.  
  926.  
  927. /* close down the graphics system 
  928.    print an error message
  929.    stop the program.
  930. */
  931. void g_failure(char *text)
  932. {
  933.   closegraph();
  934.   fprintf(stderr,"%s\n",text);
  935.   exit(256);
  936. };
  937.  
  938.  
  939. /* get memory
  940.    if we can't then abort
  941.    entry: assume we will be in graphics mode
  942. */
  943. void *g_malloc(int siz)
  944.  
  945. {
  946.   void *mem;
  947.  
  948.   mem = malloc(siz+3);
  949.   if (mem==NULL) {
  950.     g_failure("Out of memory\n");
  951.   };
  952.   return(mem);
  953. };
  954.  
  955.  
  956.  
  957. struct submenu example;
  958.  
  959. extern struct submenu *rootmenu=0;
  960. struct submenu *curmenu;
  961.  
  962. struct submenu *newmenu(fn *nofn)
  963. {
  964.   struct submenu *it;
  965.  
  966.   it =  g_malloc(sizeof(example));
  967.   it->direction = VERTICAL;
  968.   it->choicekey = 0;    /* how to choose this menu by letter from "above" */
  969.   it->lastchoice = 0;    /* which entry "below" here was chosen last time */
  970.   it->shortname = "unknown";
  971.   it->longname = "unknown title line";
  972.   it->funct = nofn;
  973.   it->style = 9;
  974.  
  975.  
  976.   it->next = 0;
  977.   it->prev = 0;
  978.   it->sub = 0;
  979.   it->esc = 0;
  980.  
  981.   it->startx = 0;
  982.   it->starty = 0;
  983.   it->belowx = 0;
  984.   it->belowy = 0;
  985.   it->sizex = 0;
  986.   it->sizey = 0;
  987.  
  988.   return(it);
  989. };
  990.  
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997. int convert_case = 1;    /* 0=don't convert lower to upper 1=do */
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003. void def_submenu(char choice, char *sname, char *lname)
  1004. {
  1005.   struct submenu *it, *sub1;
  1006.  
  1007.  
  1008.   it = newmenu(nofn);
  1009.  
  1010.   it->choicekey = lkeyof(choice);    /* how this sub-menu is activated */
  1011.   /* funct defaults to nothing */
  1012.   it->shortname = sname;
  1013.   it->sizex = boxsizex(sname);
  1014.   it->sizey = boxsizey(sname);
  1015.   it->longname = lname;
  1016.  
  1017.  
  1018.   curmenu->next = it;        
  1019.   it->prev = curmenu;
  1020.   it->next = 0;
  1021.   it->esc = curmenu->esc;
  1022.  
  1023.  
  1024.   sub1 = newmenu(nofn);
  1025.   it->sub = sub1;
  1026.   /* make a root for the submenu so that we don't need to make a flag
  1027.      which would determine whether the next 'newmenu' is supposed to 
  1028.      attach to the 'next' or to the 'sub'.   Since we have this dummy
  1029.      root, everything attaches to the 'next' and this root attaches to
  1030.      the 'sub'. */
  1031.   sub1->esc = it;
  1032.   sub1->direction = INVISIBLE;
  1033.  
  1034.  
  1035.   /* how do we define sub1, other than as a root? */
  1036.  
  1037.  
  1038.  
  1039.   curmenu = sub1;    /* curmenu=curmenu->next; curmenu=curmenu->sub; */
  1040.  
  1041.  
  1042. #ifdef DEBUG
  1043.   fprintf(dbout,"def_submenu %s\n",sname);
  1044. #endif
  1045. };
  1046.  
  1047.  
  1048.  
  1049.  
  1050. void new_fn(fn thisfn)
  1051. {
  1052.    int i;
  1053.    char fnname1[20], *fnname = fnname1;
  1054.  
  1055.   i = find_fnindex(thisfn);
  1056.   if (i==0) {
  1057.     for(i=MAXKEYS-1;i>1;i--){
  1058.       if( (hotkeyfn[i] == nofn) || (hotkeyfn[i]==0) ){
  1059.         goto add;
  1060.       };
  1061.     };
  1062.     padtext(50,150,"Ran out of room in hotkey table",8);
  1063.     i = MAXKEYS-1;
  1064.  
  1065. add:
  1066.     sprintf(fnname,"<0x%8.8lX>",thisfn);
  1067.     fkeynames[i] = strcpy( g_malloc(strlen(fnname)),fnname);
  1068.     hot_key(i,thisfn);
  1069.  
  1070.   };
  1071. };
  1072.  
  1073.  
  1074.  
  1075.  
  1076.  
  1077. void def_entry(char choice, char *sname, fn userfunct)
  1078. {
  1079.   struct submenu *it;
  1080.  
  1081.   it = newmenu(nofn);
  1082.  
  1083.   it->choicekey = lkeyof(choice);    /* how this sub-menu is activated */
  1084.   new_fn(userfunct);
  1085.   it->funct = userfunct;
  1086.   it->shortname = sname;
  1087.   it->sizex = boxsizex(sname);
  1088.   it->sizey = boxsizey(sname);
  1089.   it->longname = sname;
  1090.  
  1091.   curmenu->next = it;
  1092.   it->prev = curmenu;
  1093.  
  1094.   
  1095.   it->esc = curmenu->esc;
  1096. /*it->sub is undefined*/
  1097.  
  1098.   curmenu = it;
  1099. #ifdef DEBUG
  1100.   fprintf(dbout,"def_entry %s\n",sname);
  1101. #endif
  1102. };
  1103.  
  1104.  
  1105.  
  1106. void menu_fn(fn funct)
  1107. {
  1108.   /*
  1109.     Attach the function to the last completed menu or entry.
  1110.   */
  1111.   curmenu->funct = funct;
  1112.   new_fn(funct);
  1113. };
  1114.  
  1115.  
  1116.  
  1117. /* define function and/or direction after endef_submenu is called.
  1118. */
  1119. void menu_horizontal()
  1120. {
  1121.   curmenu->direction = HORIZONTAL;
  1122. };
  1123.  
  1124. void menu_style(int i)
  1125. {
  1126.   curmenu->style = i;
  1127. };
  1128.  
  1129.  
  1130. void menu_invisible()
  1131. {
  1132.   curmenu->direction = INVISIBLE;
  1133. };
  1134.  
  1135.  
  1136.  
  1137. void endef_submenu(char *match)
  1138. {
  1139.   char data[80];
  1140.  
  1141.   if( strcmp(match,curmenu->esc->shortname)!=0 ) {
  1142.     sprintf(data,
  1143.        "End of menu '%s' doesn't match '%s'\n",
  1144.        match,curmenu->esc->shortname);
  1145.     g_failure(data);
  1146.   };
  1147.  
  1148.   curmenu = curmenu->esc;
  1149. #ifdef DEBUG
  1150.   fprintf(dbout,"endef_submenu %s\n",sname);
  1151. #endif
  1152. };
  1153.  
  1154.  
  1155. #ifdef DEBUG
  1156. void debug_submenu (struct submenu *it)
  1157. {
  1158.   if (it!=0){ 
  1159.   fprintf(stdprn,"'%s' of '%s' at %8.8lX\n",it->shortname,it->esc->shortname,it);
  1160.     fprintf(stdprn," below=(%d,%d), size=(%d,%d)\n",
  1161.             it->belowx,it->belowy,it->sizex,it->sizey);
  1162.     fprintf(stdprn,"next ");
  1163.     debug_submenu(it->next);
  1164.     fprintf(stdprn,"sub ");
  1165.     debug_submenu(it->sub);
  1166.     fprintf(stdprn,"\n");
  1167.   };
  1168. };
  1169. #endif DEBUG
  1170.  
  1171.  
  1172. fn *donefun = nofn;    /* function that the user requested with the menus */
  1173. struct submenu *donecur;/* cursor to pass to donefun() */    
  1174. static int quitflag=0;    /* flag for total_esc feature */
  1175.  
  1176.  
  1177.  
  1178. /* footpad OFFSETS -- this defines how much space to leave around the
  1179.    requested area for a background.
  1180. */
  1181. #define PAD_X 10
  1182. #define PAD_Y 6
  1183.  
  1184. /* Routine to make a background for a menu or isolated boxtext.
  1185.    Returns a pointer to the saved graphics "below" the footpad
  1186.    which is suitable to pass to the undo_footpad routine.
  1187. */    
  1188. void *make_footpad(int x, int y, int accumx, int accumy, int style)
  1189. {
  1190.    int menuside = 1;
  1191.    void *mem;
  1192.    int lowx, lowy;
  1193.  
  1194.    lowx = x-PAD_X;
  1195.    if (lowx<0) lowx=0;
  1196.  
  1197.    lowy = y-PAD_Y;
  1198.    if (lowy<0) lowy=0;
  1199.  
  1200.     /* save the menu area from being modified (allocate mem) */
  1201.     mem = g_malloc( imagesize(
  1202.              lowx,              lowy,
  1203.              x+accumx+PAD_X,    y+accumy+PAD_Y
  1204.           ) );  
  1205.     getimage(lowx,              lowy,
  1206.              x+accumx+PAD_X,    y+accumy+PAD_Y,
  1207.       mem);
  1208.  
  1209.  
  1210.  
  1211.     /* clear area for menu */
  1212.     /* yes, i know this is one pixel smaller than the saved area in
  1213.     both the horizontal and vertical.  But turboc graphics seems
  1214.     to have a 1 pixel vertical bug somewhere and the horizontal
  1215.     is for symmetry.
  1216.     */
  1217.     setfillstyle(style,style); /* manual is ambiguous where to put style */
  1218.     bar(lowx,lowy,x+accumx+PAD_X-1,y+accumy+PAD_Y-1);
  1219.  
  1220.  
  1221.  
  1222.     if (style==1) {
  1223.       setcolor(0);
  1224.     }else{
  1225.       setcolor(15);  /* our box is going to be white */
  1226.     };
  1227.  
  1228.  
  1229.     /* IF BACKGROUND IS EMPTY (BLACK), THEN INCREASE menuside 
  1230.     if (style==0) menuside++;
  1231.     */
  1232.     rectangle(lowx+menuside,             lowy+menuside,
  1233.               x+PAD_X+accumx-menuside,   y+PAD_Y+accumy-menuside);
  1234.  
  1235.  
  1236.     return(mem);
  1237. };
  1238.  
  1239.  
  1240.  
  1241. /* routine to undo the make_footpad() routine by restoreing the saved data
  1242. */
  1243. void undo_footpad(int x, int y, void *mem)
  1244. {
  1245.   int lowx, lowy;
  1246.  
  1247.    lowx = x-PAD_X;
  1248.    if (lowx<0) lowx=0;
  1249.  
  1250.    lowy = y-PAD_Y;
  1251.    if (lowy<0) lowy=0;
  1252.  
  1253.    if (mem) {
  1254.      putimage(lowx,lowy,mem,0); 
  1255.      free(mem); 
  1256.    };
  1257.  
  1258. };
  1259.  
  1260.  
  1261. /* function to make a footpad and put a message there
  1262.    wait for a key, then remove the message 
  1263. */
  1264. void padtext(int x, int y, char *data, int style)
  1265. {
  1266.   int dx, dy;
  1267.   void *mem;
  1268.  
  1269.   dx = boxsizex(data);
  1270.   dy = boxsizey(data);
  1271.  
  1272.   if(x+dx+PAD_X+1>getmaxx()) x=PAD_X;
  1273.   if(y+dy+PAD_Y+1>getmaxy()) y=PAD_Y;
  1274.   if (  (x+dx+PAD_X+1>getmaxx()) || (y+dy+PAD_Y+1>getmaxy())  ) {
  1275.     g_failure("data given to padtext is too large for screen");
  1276.   };
  1277.  
  1278.   mem = make_footpad(x,y,dx,dy,style);
  1279.     boxtext(x,y,data);
  1280.     if (style) {
  1281.       get_stack_key();
  1282.     }else{            /* style 0 is for big errors only */
  1283.       the_key = get_key();
  1284.     };
  1285.   undo_footpad(x,y,mem);
  1286. };
  1287.  
  1288.  
  1289. int find_fnindex(fn *thisfn)
  1290. {
  1291.   int i;
  1292.  
  1293.   for(i=1;i<MAXKEYS+NUM_MYKEYS;i++){
  1294.     if (hotkeyfn[i] == thisfn) {
  1295.       return(i);
  1296.     };
  1297.   };
  1298.   return(0);
  1299. };
  1300.  
  1301.  
  1302.  
  1303.  
  1304. void meta_hotkey(struct submenu *here)
  1305. {
  1306.   int x,y;
  1307.   fn *thisfn;
  1308.   char data[80];
  1309.   int ikey;
  1310.  
  1311.   int i;
  1312.   char fnname1[40], *fnname=fnname1;
  1313.  
  1314.  
  1315.   x = here->belowx;  y = here->belowy;
  1316.   thisfn = here->funct;
  1317.         
  1318.   new_fn(thisfn);
  1319.  
  1320.   i = find_fnindex(thisfn);
  1321.   if (i) {
  1322.     fnname = fkeynames[i];
  1323.   }else{
  1324.     g_failure("Not enough room in hot key table.");
  1325.   };
  1326.  
  1327.  
  1328. add:
  1329.     padtext(x,y,"Press the key you wish to assign this function to.",0);
  1330.     /* get_stack_key(); padtext gets key for us */
  1331.     ikey = indexof(the_key);
  1332.     def_fkey(i,keynames[ikey],fnname);
  1333.     sprintf(data,"key %s assigned function %s",keynames[ikey],fnname);
  1334.     padtext(x,y,data,1);
  1335.  
  1336.     
  1337. quit:
  1338. ;    
  1339. };
  1340.  
  1341.  
  1342.  
  1343.  
  1344. void mk_invisible(struct submenu *one)
  1345. {
  1346.   one->direction = INVISIBLE;
  1347. };
  1348. void mk_horiz(struct submenu *one)
  1349. {
  1350.   one->direction = HORIZONTAL;
  1351. };
  1352. void mk_vert(struct submenu *one)
  1353. {
  1354.   one->direction = VERTICAL;
  1355. };
  1356. void delta_style(struct submenu *one)
  1357. {
  1358.   one->style--;
  1359.   if (one->style<0) one->style=14;
  1360. };
  1361.  
  1362. void mk_visible(struct submenu *one)
  1363. {
  1364.   struct submenu *each = one->esc->sub;
  1365.  
  1366.   while (each != 0) {
  1367.     each->direction = VERTICAL;
  1368.     each = each->next;
  1369.   };
  1370. };   
  1371.  
  1372. void asgn_escape(struct submenu *one)
  1373. {
  1374.   int ikey;
  1375.  
  1376.   padtext(one->belowx,one->belowy,"Which key should become <ESCAPE>?",0);
  1377.  
  1378.   ikey = indexof(the_key);
  1379.   padtext(50,50,keynames[ikey],1);
  1380.   def_fkey(KEY_ESC,       keynames[ikey],    "<KEY-ESC>"     );
  1381. };
  1382.  
  1383.  
  1384. void g_system(char *text)
  1385. {
  1386.   int i;
  1387.   savescr();
  1388.   i = system(text);
  1389.   (void) get_key();
  1390.   restorescr();
  1391.   if (i) padtext(50,50,"DOS error",5);
  1392. };
  1393.  
  1394. void short_dir()
  1395. {
  1396.   g_system("dir /w");
  1397. };
  1398.  
  1399. void long_dir()
  1400. {
  1401.   g_system("dir");
  1402. };
  1403.  
  1404. void alpha_dir()
  1405. {
  1406.   g_system("ds ne");
  1407. };
  1408.  
  1409.  
  1410. int keyready()
  1411. {
  1412.   return (  (bioskey(1)) || (keys_ptr!=0) );
  1413. };
  1414.  
  1415. static void *memory=0;    /* last value of 'memory' variable */
  1416. static int glob_x,glob_y;
  1417.  
  1418. void MM_right(struct submenu *one)
  1419. {  
  1420.   undo_footpad(glob_x,glob_y,memory);
  1421.   one->esc->sub->startx++;
  1422.  
  1423.   if (!keyready()) {
  1424.     update_submenu(one->esc->sub);
  1425.   }else{
  1426.     memory = 0;
  1427.   };
  1428. };
  1429.  
  1430. void MM_left(struct submenu *one)
  1431. {
  1432.   undo_footpad(glob_x,glob_y,memory);
  1433.   one->esc->sub->startx--;
  1434.  
  1435.   if (!keyready()) {
  1436.     update_submenu(one->esc->sub);
  1437.   }else{
  1438.     memory = 0;
  1439.   };
  1440. };
  1441. void MM_up(struct submenu *one)
  1442. {
  1443.   undo_footpad(glob_x,glob_y,memory);
  1444.   one->esc->sub->starty--;
  1445.  
  1446.   if (!keyready()) {
  1447.     update_submenu(one->esc->sub);
  1448.   }else{
  1449.     memory = 0;
  1450.   };
  1451. };
  1452. void MM_down(struct submenu *one)
  1453. {
  1454.   undo_footpad(glob_x,glob_y,memory);
  1455.   one->esc->sub->starty++;
  1456.  
  1457.   if (!keyready()) {
  1458.     update_submenu(one->esc->sub);
  1459.   }else{
  1460.     memory = 0;
  1461.   };
  1462. };
  1463.  
  1464. void DOSshell()
  1465. {
  1466.   g_system("");
  1467. };
  1468.   
  1469.  
  1470. /* this must be called before anything else may be called. 
  1471.    initgr() should be called before this.
  1472. */
  1473. void menu_init()
  1474. {
  1475.   rootmenu = newmenu(nofn);
  1476.   curmenu = rootmenu;
  1477.   rootmenu->direction = INVISIBLE;
  1478.   rootmenu->shortname = "rootmenu";
  1479.   rootmenu->longname = "";
  1480.   rootmenu->esc = rootmenu;
  1481.   rootmenu->sub = rootmenu;
  1482.   rootmenu->belowx = 0;
  1483.   rootmenu->belowy = 0;
  1484.  
  1485.   init_keys();
  1486.   init_fkeys();
  1487.  
  1488.   menu_horizontal();    /* default is vertical */
  1489.   user_menus();
  1490.   def_submenu('U',"Utilities","--- utilities ---");
  1491.     def_submenu('K',"Keys"," -- key utilities -- ");
  1492.       def_entry('H',"assign Hotkey to menu entry's function",meta_hotkey);
  1493.       def_entry('E',"assign Escape key",asgn_escape);
  1494.       def_entry('M',"define key Macro",mk_macro);
  1495.       def_entry('U',"Undefine macro",undo_macro);
  1496.  
  1497. /*
  1498.     do this just like assign escape key, but let them pick
  1499.     which key will be assigned
  1500.       def_entry('F',"define a function key",nofn);
  1501.  
  1502.     If a keyboard lkey or a hotkey function has the wrong name
  1503.     or no name at all, then these features will allow the user
  1504.     to correct that.
  1505.       def_entry('N',"Give an ASCII name to a keyboard key",nofn);
  1506.       def_entry('n',"Give an ASCII name to a hotkey function",nofn);
  1507. */
  1508.     endef_submenu("Keys");
  1509.  
  1510.     def_submenu('M',"Menus"," -- hotkey menu utilities -- ");
  1511.       def_entry('C',"Change background color",delta_style);
  1512.       def_entry('H',"Make menu horizontal",mk_horiz);
  1513.       def_entry('V',"Make menu vertical",mk_vert);
  1514.       def_entry('I',"Make menu entry invisible",mk_invisible);
  1515.       def_entry('V',"Make entries visible in this menu",mk_visible);
  1516.       def_submenu('M',"Move menu","moving menus on the screen");    
  1517.         def_entry('R',"to the Right",MM_right);
  1518.         def_entry('L',"to the Left",MM_left);
  1519.         def_entry('U',"Upward",MM_up);
  1520.         def_entry('D',"Downward",MM_down);
  1521.       endef_submenu("Move menu");
  1522. /*
  1523.       def_entry('P',"Prune menu entry",nofn);
  1524.       def_entry('G',"Graft menu entry",nofn);
  1525. */
  1526.     endef_submenu("Menus");
  1527.     def_submenu('D',"Disk","     -- disk stuff --     ");
  1528. /*
  1529.       def_entry('C',"Change subdirectory",nofn);
  1530. */
  1531.       def_entry('L',"show Long directory",long_dir);
  1532.       def_entry('S',"show Short directory",short_dir);
  1533.       def_entry('A',"Alphabetize directory",alpha_dir);
  1534.       def_entry('D',"DOS shell",DOSshell);
  1535.       def_entry('W',"Write configuration to disk",write_config);
  1536.       def_entry('R',"Read configuration from disk",read_config);
  1537.  
  1538.     endef_submenu("Disk");
  1539.   endef_submenu("Utilities");
  1540. };
  1541.  
  1542.  
  1543.  
  1544.  
  1545.  
  1546. /* size and print a menu on the display using a backdrop and boxes.
  1547.    (save old contents of area)
  1548. */
  1549. void update_submenu(struct submenu *it)
  1550. {
  1551.   int ax, ay;
  1552.   int maxx, maxy;
  1553.  
  1554.  
  1555.   maxx = getmaxx();
  1556.   maxy = getmaxy();
  1557.  
  1558.   
  1559.  
  1560.  
  1561.   /* check to see if the menu has an starting point */
  1562.   ax = (it->esc->sub->startx);
  1563.   ay = (it->esc->sub->starty);
  1564.   if( (ax!=0) || (ay!=0) ) {
  1565.     glob_x = ax;
  1566.     glob_y = ay;
  1567.   }else{    /* if not, use default */
  1568.     glob_x = it->esc->belowx+PAD_X;
  1569.     glob_y = it->esc->belowy+PAD_Y;
  1570.   };
  1571.  
  1572.  
  1573.   /* this sets up the accumx and accumy locations */
  1574.   prep_submenu(it);    /* measure size of menu */
  1575.  
  1576.  
  1577.   if (glob_x+PAD_X+accumx+1>maxx) glob_x=PAD_X;
  1578.   if (glob_y+PAD_Y+accumy+1>maxy) glob_y=PAD_Y;
  1579.  
  1580.   if( (glob_x+PAD_X+accumx+1>maxx) || (glob_y+PAD_Y+accumy+1>maxy) ) {
  1581.     g_failure("Menu doesn't fit on screen\n");
  1582.   };
  1583.  
  1584.   /* whatever the starting point for the menu turns out to be
  1585.      SAVE IT FOR LATER
  1586.   */
  1587.   it->esc->sub->startx = glob_x;
  1588.   it->esc->sub->starty = glob_y;
  1589.  
  1590.  
  1591.   /* make an area for the menu */
  1592.   memory = make_footpad(glob_x,glob_y,accumx,accumy,it->esc->style);
  1593.  
  1594.   /* dump menu in glob_x,glob_y footpad */
  1595.   dump_submenu(glob_x,glob_y,it); 
  1596. };
  1597.  
  1598.  
  1599.  
  1600. /* print the menu, get the action, remove the menu
  1601. */
  1602. int run_submenu(struct submenu *it)
  1603. {
  1604.   int retval;
  1605.  
  1606.   if (it==0) return(0);  
  1607.   it->funct(it);
  1608.  
  1609.  
  1610.     /* this makes glob_x and glob_y,
  1611.        saves the background,
  1612.        and puts the menu on the screen
  1613.     */
  1614.     update_submenu(it);
  1615.  
  1616.  
  1617.     /* use the menu */
  1618.     retval = key_submenu(it);
  1619.  
  1620.  
  1621.     /* restore area that was saved (release memory) */
  1622.     undo_footpad(glob_x,glob_y,memory);
  1623.     memory = 0;
  1624.  
  1625.   return(retval);
  1626. };
  1627.  
  1628.  
  1629.  
  1630.  
  1631. int subrun_submenu(struct submenu *it)
  1632. {
  1633.   void *savemem;
  1634.   int savex, savey;
  1635.  
  1636.   if (it==0) return(quitflag);
  1637.  
  1638.  
  1639.   /* if submenu doesn't exist, then just execute the function */
  1640.   if( (it->sub==0) || (it == it->sub) ) {
  1641.     donefun = it->funct;
  1642.     donecur = it;
  1643.     quitflag = 1;
  1644.  
  1645.     /* totally quit this menu so we can run the 'donefun' function */
  1646.     return(quitflag);    
  1647.   };
  1648.  
  1649.  
  1650.   /* here we save the global variable 'memory' so that it remains a global
  1651.      and can be accessed globally, and yet it is local to the level of the
  1652.      menu that we are on and is not destroyed.
  1653.   */
  1654.   savemem = memory;
  1655.   savex = glob_x;
  1656.   savey = glob_y;
  1657.     quitflag = run_submenu(it->sub);
  1658.   glob_x = savex;
  1659.   glob_y = savey;
  1660.   memory = savemem;
  1661.  
  1662.  
  1663.   return(quitflag);
  1664. };
  1665.  
  1666.  
  1667.  
  1668.  
  1669.  
  1670.  
  1671.  
  1672. /* find the index for a keyboard key given it's name
  1673. */
  1674. int indexofname(char *name)
  1675. {
  1676.   int i;
  1677.  
  1678.   for(i=0;i<LASTKEY;i++){
  1679.     if( strcmp(keynames[i],name)==0 ){
  1680.       return(i);
  1681.     };
  1682.   };
  1683.   return(0);
  1684. };
  1685.  
  1686.  
  1687.  
  1688.  
  1689. /* find the long word that the keyboard will give for a character
  1690.    find it given that we know the character's ASCII value
  1691. */  
  1692. long int lkeyof(char ch)
  1693. {
  1694.   char  d0[10], *data=d0;
  1695.  
  1696.   switch (ch) {
  1697.     case '\t' :
  1698.     data = "[TAB]";
  1699.     case '\n' :
  1700.     data = "[ENTER]";
  1701.     default : 
  1702.     data[0] = '[';
  1703.     data[1] = ch;
  1704.     data[2] = ']';
  1705.     data[3] = '\0';
  1706.   };
  1707.  
  1708.   return(  keys[ indexofname(data) ]   );
  1709. };
  1710.  
  1711.  
  1712.  
  1713.  
  1714. /* find the index of a keyboard key given the keyboard long word 
  1715. */
  1716. int indexof(long int lkey)
  1717. {
  1718.   int i;
  1719.  
  1720.   for (i=0;i<LASTKEY;i++){
  1721.     if (  lkey == keys[i]  ) return(i);
  1722.   };
  1723.   return(0);
  1724. };
  1725.  
  1726.  
  1727.  
  1728. /* find the last entry of the macro
  1729. */
  1730. struct mac *lastof(struct mac *mac)
  1731. {
  1732.   struct mac *amac = mac;
  1733.  
  1734.   if (amac==0) return(amac);
  1735.  
  1736. top:
  1737.   if (amac->next==0) return(amac);
  1738.   amac = amac->next;
  1739.   goto top;
  1740. };
  1741.  
  1742.  
  1743. /* get the next key off the stack
  1744.    or get another key from the keyboard if the stack is empty
  1745.    if the keyboard key is a macro, then expand it and put it on the stack.
  1746. */
  1747. void get_stack_key()
  1748. {
  1749. /*int fkey;             * function key value */
  1750.   int ikey;            /* index into key table */
  1751.   struct mac *amacro;
  1752.  
  1753.   if (keys_ptr) {
  1754.     the_key = keystack[--keys_ptr];
  1755.   }else{
  1756.  
  1757.     the_key = get_key();
  1758.     ikey = indexof(the_key);
  1759.     if (ikey) {
  1760.       amacro = lastof(mac[ikey]);
  1761.       if (amacro) {
  1762.         while (amacro){  
  1763.           keystack[keys_ptr++] = amacro->fkey;
  1764.           amacro = amacro->prev;
  1765.         };
  1766.         the_key = keystack[--keys_ptr];
  1767.       };
  1768.     };
  1769.  
  1770.   };
  1771. };
  1772.  
  1773.  
  1774.  
  1775.  
  1776. /* this puts a cursor around the submenu item
  1777. we want to change this [;] to invert the area of the screen.
  1778. */
  1779. void cursdo(struct submenu *it)
  1780. {
  1781.  
  1782.   if (it->prev != 0) {
  1783. #define CURSMARG 2
  1784.     rectangle(it->startx+CURSMARG,
  1785.               it->starty+CURSMARG, 
  1786.               it->startx+it->sizex-CURSMARG,
  1787.               it->starty+it->sizey-CURSMARG
  1788.          );
  1789.   };
  1790. };
  1791.  
  1792. void curson(struct submenu *it)
  1793. {
  1794.   setcolor(15);
  1795.   cursdo(it);
  1796. };
  1797. void cursoff(struct submenu *it)
  1798. {
  1799.   setcolor(00);
  1800.   cursdo(it);
  1801. };
  1802.  
  1803.  
  1804.  
  1805.  
  1806.  
  1807. /* Get a key from the stack.
  1808.    Check to see if it is a hot key, if so do it's routine.
  1809.    Save key value in global location.
  1810. */
  1811. void call_for_key(struct submenu *cursor)
  1812. {
  1813.   int i;
  1814.  
  1815.   get_stack_key();
  1816.  
  1817.   /* now call function assigned to the fkey 
  1818.   */  
  1819.   if(  (the_key>0) && (the_key <= MAXKEYS+NUM_MYKEYS)  ){
  1820.     i = (int) the_key;
  1821.     if (hotkeyfn[i]) if (enable_hotkeys) {
  1822.       cursoff(cursor);
  1823.       hotkeyfn[i](cursor);
  1824.       curson(cursor);
  1825.     };
  1826.   };
  1827. };
  1828.  
  1829.  
  1830.  
  1831.  
  1832.  
  1833.  
  1834.  
  1835. struct mac *new_mac()
  1836. {
  1837.   struct mac *it;
  1838.  
  1839.   it = g_malloc( sizeof(*it) );
  1840.   return (it);
  1841. /*
  1842.   it->next=0;
  1843.   it->prev=0;
  1844.   it->fkey=0;
  1845. */
  1846. };
  1847.  
  1848.  
  1849.  
  1850. void macs_free(struct mac *start)
  1851. {
  1852.   struct mac *nxt, *it=start;
  1853.  
  1854.   while (it!=0) {
  1855.     nxt = it->next;
  1856.     free(it);
  1857.     it = nxt;
  1858.   };
  1859. };
  1860.  
  1861.  
  1862. /* find the name of a keyname or function
  1863. */
  1864. char last_kname1[40], *last_kname = last_kname1;
  1865. char *find_keyname(long int lkey)
  1866. {
  1867.   int ikey;
  1868.  
  1869.   ikey = indexof(lkey);
  1870.   if (ikey) {
  1871.     sprintf(last_kname,"%s",keynames[ikey]);
  1872.   }else{
  1873.     if(  (lkey>0) && (lkey <= MAXKEYS+NUM_MYKEYS)  ){
  1874.       ikey = (int) lkey;
  1875.       sprintf(last_kname,"%s",fkeynames[ikey]);
  1876.     }else{
  1877.       sprintf(last_kname,"[%8.8lX]",lkey);
  1878.     };
  1879.   };
  1880.  
  1881.   return(last_kname);
  1882. };
  1883.  
  1884.  
  1885.  
  1886. struct mac *get_macs()
  1887. {
  1888.   struct mac *last, *amac, *first;
  1889.  
  1890.  
  1891.   last = new_mac();
  1892.   last->next = 0;
  1893.   last->prev = 0;
  1894.   last->fkey = 0;    /* make a token/spacer node which we will delete later */
  1895.  
  1896.   first = last;
  1897.  
  1898. top:
  1899.   get_stack_key(); 
  1900.  
  1901.   if(  (the_key == KEY_ESC) && (keys_ptr==0) ){
  1902.     amac = first->next;
  1903.     free(first);
  1904.     amac->prev=0;    /* don't forget this -- it'll take you hours to fix */
  1905.     return(amac);
  1906.   };
  1907.  
  1908.   printf("%s",find_keyname(the_key));
  1909.  
  1910.   amac = new_mac();
  1911.   amac->fkey = the_key;
  1912.   amac->prev = last;
  1913.   amac->next = 0;
  1914.  
  1915.   last->next = amac;
  1916.   last = last->next;
  1917.   goto top;
  1918.  
  1919.  
  1920. };
  1921.  
  1922.  
  1923.  
  1924. /* function to initialize the graphics system for whatever hardware
  1925.    the user's computer happens to have.
  1926.    Used by restorescr() to 'undo' the effect of closegraph() from savescr();
  1927.    Something like this should be called by the user before menu_init() to turn
  1928.    on the graphics system.
  1929. */
  1930. void initgr()
  1931. {
  1932.   int gd=DETECT;
  1933.   int gm=HERCMONOHI;
  1934.   char *pth = "D:\\TC";
  1935.  
  1936.  
  1937.   initgraph(&gd, &gm, pth);
  1938.   if (gd<0) {
  1939.     closegraph();
  1940.     fprintf(stderr,"fail %d",gd);
  1941.     exit(256);
  1942.   };
  1943.   /* graphdefaults(); */
  1944.  
  1945. };
  1946.  
  1947.  
  1948.  
  1949. /* function (nonrecursive) to save the screen and jump to text
  1950.    so that processing may occur in text mode (disk i/o and such)
  1951.    savescr must be called before restorescr can be called.
  1952. */
  1953. static void *scrdata=0;
  1954. static fn *old_wait_key=nofn;
  1955. void savescr()
  1956. {
  1957.   if (scrdata==0) scrdata = g_malloc( imagesize(0,0,getmaxx(),getmaxy()) );  
  1958.   getimage(0,0,getmaxx(),getmaxy(),scrdata);
  1959.   closegraph();
  1960.  
  1961.   old_wait_key = the_wait_key;
  1962.   the_wait_key = my_wait_key;
  1963.  
  1964.   enable_hotkeys=0;
  1965. };
  1966.  
  1967. /* function (nonrecursive) to restore the screen and jump back to graphics.
  1968.    This is the opposite of savescr();
  1969.    savescr must be called first.
  1970. */
  1971. void restorescr()
  1972. {
  1973.   initgr();    /* init graphics */  
  1974.   if (scrdata) putimage(0,0,scrdata,0);
  1975.  
  1976.   the_wait_key = old_wait_key;
  1977.   old_wait_key = nofn;
  1978.  
  1979.   enable_hotkeys=1; /* hope it wasn't 0 on call to savescr */
  1980. };
  1981.  
  1982.  
  1983.  
  1984.  
  1985.  
  1986. void undo_macro(struct submenu *one)
  1987. {
  1988.   int ikey;
  1989.   int x,y;
  1990.  
  1991.   x = one->belowx;
  1992.   y = one->belowy;
  1993.   padtext(x,y,"Press the key from which you wish to UNASSIGN a macro.",0);
  1994.  
  1995.   /* lkey = get_key(); */
  1996.   ikey = indexof(the_key);
  1997.   if (ikey) {
  1998.     if (mac[ikey]) macs_free(mac[ikey]);
  1999.     mac[ikey] = 0;
  2000.   }else{
  2001.     padtext(x,y,"Internal problem.",8);
  2002.   };
  2003.  
  2004. };
  2005.  
  2006.  
  2007.  
  2008. void mk_macro()
  2009. {
  2010.   long int lkey;
  2011.   int ikey;
  2012.   struct mac *new;
  2013.  
  2014.   savescr();
  2015.  
  2016.   printf("\
  2017.                           --- Macro facility ---  \n\
  2018. \n\
  2019. This utility allows you to define which keys will be pressed for you whenever\n\
  2020. you press a given key.  So, for example, you can assign F9 to go into the menus\n\
  2021. and enter this utility.\n\
  2022. \n\
  2023. Press the key to which you wish to assign a macro: ");
  2024.  
  2025.  
  2026.  
  2027.   lkey = get_key();
  2028.   ikey = indexof(lkey);
  2029.   printf("%s\n",keynames[ikey]);
  2030.  
  2031.   if ( mac[ikey] ) {
  2032.     printf("\n\
  2033.           ----->>>>> warning: macro already exists.\n\
  2034.           Press the macro key to see it's expansion.\n\n");
  2035.   };
  2036.  
  2037.   printf("\
  2038. Now type the keys that the macro key will expand as.\n\
  2039. Press the <ESCAPE> function when you are done.\n");
  2040.  
  2041.   new = get_macs();
  2042.   if (mac[ikey]) macs_free(mac[ikey]);
  2043.   mac[ikey] = new;
  2044.  
  2045.  
  2046.   restorescr();
  2047.  
  2048. };
  2049.  
  2050.  
  2051.  
  2052.  
  2053.  
  2054. void menu_run()            /* how to run the menu system */
  2055. {
  2056.   if (debug1) boxtext(100,150,"menu_run");
  2057.  
  2058.   do {
  2059.     (void) run_submenu(rootmenu); /* 1=TOTAL_ESC, 0=ESC */
  2060.  
  2061.     memory = 0;
  2062.     donefun(donecur);    /* execute the requested function */
  2063.     donefun = nofn;    /* cancel any previous menu function executed */
  2064.     donecur = NULL;
  2065.     /* turn off menu from hotkey
  2066.     this fixes the bug of 'what if the menu move is executed from the
  2067.     menu instead of from a hot key?  Then the menus are turned off
  2068.     (quitflag and donefun) and the function cannot move the menu!
  2069.     So we use 'memory' to keep track of these things...
  2070.     */
  2071.     if (memory) {
  2072.       undo_footpad(glob_x,glob_y,memory); 
  2073.       memory = 0;
  2074.     };
  2075.  
  2076.     quitflag = 0;
  2077.  
  2078.   } while (keys_ptr);
  2079.  
  2080. };
  2081.  
  2082.  
  2083.  
  2084.  
  2085. void doeach_entry(struct submenu *it, void funct(struct submenu *q)  )
  2086. {
  2087.   struct submenu *each = it->next;
  2088.  
  2089.   if (debug2) {
  2090.     boxtext(100,110,"doeach_entry");
  2091.     boxtext(100,122,it->shortname);
  2092.     boxtext(100,134,each->next->shortname);
  2093.   };
  2094.  
  2095.     while (each != 0) {
  2096.       if(  (each->direction != INVISIBLE) || (debug2) ){
  2097.         funct(each);
  2098.       };   
  2099.       each = each->next;
  2100.     };
  2101. };   
  2102.  
  2103.  
  2104.  
  2105. int maxof(int a, int b)
  2106. {
  2107.   if (a<=b) return(b);
  2108.   return(a);
  2109. };
  2110.  
  2111.  
  2112.  
  2113. void accum_size(struct submenu *one)
  2114. {
  2115.  
  2116.   if (debug2) boxtext(50,250,"accum_size");
  2117.  
  2118.   if (one->esc->direction == HORIZONTAL) {
  2119.     accumx = accumx + one->sizex;
  2120.     accumy = maxof(accumy,one->sizey);
  2121.   }else{
  2122.     accumx = maxof(accumx,one->sizex);
  2123.     accumy = accumy + one->sizey;
  2124.   };
  2125.  
  2126. };
  2127.  
  2128.  
  2129. /* size up a menu for a box */
  2130. void prep_submenu(struct submenu *it)
  2131. {
  2132.  
  2133.   if (debug1) boxtext(0,170,"prep_submenu");
  2134.  
  2135.   /* don't matter whether we are horiz or vert */
  2136.     accumx = 0;
  2137.     accumy = 0;
  2138.  
  2139.   if (it->esc->longname) {
  2140.     if (strlen(it->esc->longname)) {
  2141.       accumx = boxsizex(it->esc->longname);
  2142.       accumy = boxsizey(it->esc->longname);
  2143.     };
  2144.   };
  2145.   doeach_entry(it,accum_size);
  2146.   
  2147.  
  2148.   if (debug1) boxtext(130,170,"prep done");
  2149. };
  2150.  
  2151.  
  2152.  
  2153.  
  2154. void dump_text(struct submenu *one)
  2155. {
  2156. #ifdef DEBUG
  2157.   char d1[80],*data=d1;
  2158.   if (debug2) {
  2159.     boxtext(250,120,"dump_text");
  2160.     boxtext(250,131,one->shortname);
  2161.     sprintf(data,"(%d,%d)",accumx,accumy);
  2162.     boxtext(250,142,data);
  2163.   };
  2164. #endif
  2165.  
  2166.  
  2167.   one->startx = accumx;
  2168.   one->starty = accumy;
  2169.   boxtext(accumx,accumy,one->shortname);
  2170.   if (one->esc->direction == HORIZONTAL) {
  2171.     one->belowx = accumx;
  2172.     one->belowy = accumy + one->sizey;
  2173.     accumx += one->sizex; /* boxsizex(one->shortname); */
  2174.   }else{
  2175.     one->belowx = accumx + one->sizex;
  2176.     one->belowy = accumy;
  2177.     accumy += one->sizey; /* boxsizey(one->shortname); */
  2178.   };
  2179.  
  2180. };
  2181.  
  2182.  
  2183.  
  2184. void dump_submenu(int x, int y, struct submenu *it)
  2185. {  
  2186.   if (debug1) boxtext(0,130,"dump_submenu");
  2187.  
  2188.   accumx = x;
  2189.   accumy = y;
  2190.     
  2191.   if (it->esc->longname) {
  2192.     if (strlen(it->esc->longname)) {
  2193.   
  2194.       boxtext(accumx,accumy,it->esc->longname);
  2195.       if (it->esc->direction == HORIZONTAL) {
  2196.         accumx += boxsizex(it->esc->longname); 
  2197.       }else{
  2198.         accumy += boxsizey(it->esc->longname); 
  2199.       };  
  2200.   
  2201.     };
  2202.   };
  2203.  
  2204.  
  2205.   doeach_entry(it,dump_text);
  2206.  
  2207.   if (debug1) boxtext(100,130,"dump done");
  2208. };
  2209.  
  2210.  
  2211.  
  2212.  
  2213.  
  2214. void matchkey(struct submenu *one)
  2215. {
  2216. /* note that if we don't check the quitflag here, then 
  2217.     if we are nested in several submenus
  2218.     and the same key is used on different levels
  2219.     then when the key is pressed, it could be taken to mean 2 functions
  2220.     so by checking the quitflag, we take it to mean only 1 function.
  2221.    We could have cleared 'the_key' instead, but that would be logical.
  2222. */
  2223.   if (!quitflag) {
  2224.     if (the_key == one->choicekey) {
  2225.       quitflag = subrun_submenu(one);
  2226.     };
  2227.  
  2228.     /* Here we convert lower case letters to upper case and try again to match.
  2229.        I don't see any point in making the convert_case variable local to each
  2230.     menu.
  2231.        We rely on the fact that the long word keyboard alphabet is linear in
  2232.     both the upper and lower case sequences.
  2233.     */
  2234.     if (convert_case) {
  2235.       if( (lkeyof('a')<= the_key) && (lkeyof('z')>= the_key) ){
  2236.         if ( (the_key-lkeyof('a')+lkeyof('A')) == one->choicekey) {
  2237.       quitflag = subrun_submenu(one);
  2238.         };
  2239.       };
  2240.     };
  2241.  
  2242.   };
  2243. };
  2244.  
  2245.  
  2246.  
  2247.  
  2248.  
  2249.  
  2250. /* here we go to next item, skipping any invisible items */
  2251. struct submenu *cur_next(struct submenu *oldcursor)
  2252. {
  2253.    struct submenu *cursor = oldcursor;
  2254.  
  2255.    cursoff(cursor);
  2256.    if (cursor->next) {
  2257.       cursor = cursor->next;
  2258.       while( (cursor->direction==INVISIBLE) && (cursor->next != 0) ) {
  2259.         cursor = cursor->next;
  2260.       };
  2261.       if (cursor->direction==INVISIBLE) cursor = oldcursor;
  2262.    };
  2263.    curson(cursor);
  2264.    return(cursor);
  2265. };
  2266.  
  2267.  
  2268. /* here we go to previous item, skipping any invisible items */
  2269. struct submenu *cur_prev(struct submenu *oldcursor)
  2270. {
  2271.    struct submenu *cursor = oldcursor;
  2272.  
  2273.    cursoff(cursor);
  2274.    if (cursor->prev) {
  2275.       cursor = cursor->prev;
  2276.       while( (cursor->direction==INVISIBLE) && (cursor->prev != 0) ) {
  2277.         cursor = cursor->prev;
  2278.       };
  2279.       /* if (cursor->direction==INVISIBLE) cursor = oldcursor; */
  2280.    };
  2281.    curson(cursor);
  2282.    return(cursor);
  2283. };
  2284.  
  2285.  
  2286. /* do all key processing for this menu
  2287.   return 0 for normal termination or 1 for TOTAL_QUIT
  2288. */
  2289. int key_submenu(struct submenu *it)
  2290. {
  2291.   struct submenu *cursor = it;
  2292.  
  2293.   if (debug1) boxtext(0,140,"key_submenu");
  2294.  
  2295. top:
  2296.   curson(cursor);
  2297.   call_for_key(cursor);    /* needs cursor for hotkey function calling */
  2298.  
  2299.   if (debug1) boxtext(50,140,"got key");
  2300.  
  2301.   if (the_key == KEY_ESC) {
  2302.     cursoff(cursor);
  2303.     return(0);
  2304.   };
  2305.   if (the_key == KEY_TOTAL_ESC) {
  2306.     cursoff(cursor);
  2307.     return(1); 
  2308.   };
  2309.  
  2310. /* cursor movement */
  2311.   if (the_key == KEY_RIGHT) {    
  2312.     cursor = cur_next(cursor);
  2313.   };
  2314.   if (the_key == KEY_LEFT) {    
  2315.     cursor = cur_prev(cursor);
  2316.   };
  2317.  
  2318.   if (the_key == KEY_DOWN) {
  2319.     if (it->esc->direction == HORIZONTAL) {
  2320.       quitflag = subrun_submenu(cursor);
  2321.     }else{
  2322.       cursor = cur_next(cursor);
  2323.     };      
  2324.   };
  2325.  
  2326.   if (the_key == KEY_UP) {
  2327.     if (it->esc->direction == HORIZONTAL) {
  2328.       cursoff(cursor);
  2329.       return(0);
  2330.     }else{
  2331.       cursor = cur_prev(cursor);
  2332.     };
  2333.   };
  2334.  
  2335.  
  2336.   if (the_key == KEY_SUB) {    
  2337.     quitflag = subrun_submenu(cursor);
  2338.   };
  2339.  
  2340.   if (debug1) boxtext(120,140,"almost");
  2341.  
  2342.   cursoff(cursor);
  2343.   doeach_entry(it,matchkey);
  2344.   if (quitflag) {
  2345.     return(quitflag);  
  2346.   };
  2347.  
  2348.   curson(cursor);
  2349.   goto top;
  2350. };
  2351.  
  2352.  
  2353.  
  2354.  
  2355. int def_fkey(int fkey, char *keyname, char *fkeyn)
  2356. {
  2357.   int ikey;
  2358.   char *data;
  2359.  
  2360.   ikey = indexofname(keyname);
  2361.   if (ikey) {
  2362.     if (mac[ikey]) macs_free(mac[ikey]);
  2363.     mac[ikey] = new_mac();
  2364.     mac[ikey]->fkey = fkey;
  2365.     mac[ikey]->next = 0;
  2366.     mac[ikey]->prev = 0;
  2367.  
  2368.     if (!fkeynames[fkey]) goto over;
  2369.     if (strcmp(fkeyn,fkeynames[fkey])!=0) {
  2370. over:
  2371.       data = (char *) g_malloc(strlen(fkeyn));
  2372.       strcpy(data,fkeyn);
  2373.       fkeynames[fkey] = data;
  2374.     };
  2375.  
  2376.     return(1);
  2377.   };
  2378.   return(0);
  2379. };
  2380.  
  2381.  
  2382.  
  2383.  
  2384. #define configfile "MENU.TMP"
  2385. /* the default name of the file where the config data is written */
  2386.  
  2387.  
  2388.  
  2389. FILE *Fconfig;
  2390.  
  2391.  
  2392. /* this routine writes out the config data to the default file.
  2393.    if the file cannot be written, the user is prompted for a name.
  2394. */
  2395. void write_config()
  2396. {
  2397.   int i;
  2398.   struct mac *amac;
  2399.  
  2400.   Fconfig = fopen(configfile,"w");
  2401.   fprintf(Fconfig,"%s\n","__TIME__ __DATE__");
  2402.  
  2403.  
  2404.  
  2405.   fprintf(Fconfig,"%d\n",lastkey);
  2406.   for(i=0;i<lastkey;i++){
  2407.     fprintf(Fconfig,"%8.8lX\n%s\n",keys[i],keynames[i]);
  2408.   };
  2409.  
  2410.   for(i=1;i<=MAXKEYS+NUM_MYKEYS;i++){
  2411.     if( (hotkeyfn[i]!=0) || (fkeynames[i]!=0) ){
  2412.       if (fkeynames[i]==0) fkeynames[i] = "unknown";
  2413.       fprintf(Fconfig,"%d\n",i);
  2414. /*
  2415.       fprintf(Fconfig,"%X\n",hotkeyfn[i]);
  2416. */
  2417.       fprintf(Fconfig,"%s\n",fkeynames[i]);
  2418.     };
  2419.   };
  2420.   fprintf(Fconfig,"%d\n",0);
  2421.  
  2422.  
  2423.   for (i=0;i<lastkey;i++){
  2424.     if (mac[i]) {
  2425.       amac = mac[i];
  2426.       fprintf(Fconfig,"%s\n",keynames[i]);
  2427.       while (amac !=0) {
  2428.     fprintf(Fconfig,"%s\n",find_keyname(amac->fkey));
  2429.     amac = amac->next;
  2430.       };
  2431.       fprintf(Fconfig,"\n");
  2432.     };
  2433.   };
  2434.   fprintf(Fconfig,"endofmacros\n");
  2435.  
  2436. /*
  2437.   dump rootmenu
  2438. */
  2439.  
  2440.  
  2441.  
  2442.  
  2443.   fclose(Fconfig);
  2444. };
  2445.  
  2446.  
  2447.  
  2448.  
  2449.  
  2450.  
  2451.  
  2452.  
  2453. char *readstr(char *data)
  2454. {
  2455.   int len;
  2456.   
  2457.     fgets(data,70,Fconfig);
  2458.     len = strlen(data); 
  2459.     data[len-1]='\0';
  2460.     return(  strcpy(g_malloc(len-1),data)  );
  2461. };
  2462.  
  2463.  
  2464.  
  2465. long int lkeyofname(char *name)
  2466. {
  2467.   int i;
  2468.  
  2469.   i = indexofname(name);
  2470.   if (i==0) {
  2471.     for(i=1;i<=MAXKEYS+NUM_MYKEYS;i++){
  2472.       if(strcmp(fkeynames[i],name)==0) {
  2473.         return(i);
  2474.       };
  2475.     };
  2476.     return(0);
  2477.   }else{
  2478.     return(keys[i]);
  2479.   };
  2480. };
  2481.  
  2482.  
  2483. void read_config()
  2484. {
  2485.   char data[80];
  2486.   int i;
  2487.   char ch;
  2488.   char *answ;
  2489.   struct mac *amac, *first;
  2490.   fn *rou;
  2491.  
  2492.  
  2493.   Fconfig = fopen(configfile,"r");
  2494.  
  2495.   answ = readstr(data);
  2496. /*
  2497.   if (strcmp(answ,"__TIME__ __DATE__")!=0) {
  2498.     padtext(50,50,answ,3);
  2499.   };
  2500. */
  2501.  
  2502.  
  2503.  
  2504.   fscanf(Fconfig,"%d%c",&lastkey,&ch);
  2505.  
  2506.   for(i=0;i<lastkey;i++){
  2507.     fscanf(Fconfig,"%lx%c",&keys[i],&ch);
  2508.     keynames[i] = readstr(data);
  2509.   };
  2510.  
  2511.   while (i) {
  2512.     fscanf(Fconfig,"%d%c",&i,&ch);
  2513.     if (i) {
  2514. /*
  2515.       fscanf(Fconfig,"%x",&rou);
  2516.       hotkeyfn[i] = rou;
  2517.       fscanf(Fconfig,"%c",&ch);
  2518. */
  2519.       fkeynames[i] = readstr(data);
  2520.     };
  2521.   };
  2522.  
  2523.  
  2524.  
  2525.  
  2526.   answ = readstr(data);
  2527.   while (strcmp(answ,"endofmacros")!=0) {
  2528.     i = indexofname(answ);
  2529.     first = new_mac();
  2530.     first->prev=0;
  2531.     amac = first;
  2532.  
  2533.     answ = readstr(data);
  2534.     while (strlen(answ)) {
  2535.       amac->fkey = lkeyofname(answ);
  2536.       amac->next = new_mac();
  2537.       amac->next->prev = amac;
  2538.       amac->next->next = 0;
  2539.       amac = amac->next;
  2540.       answ = readstr(data);
  2541.     };
  2542.  
  2543.     mac[i] = first;
  2544.     amac->prev->next =0;
  2545.     free(amac);
  2546.  
  2547.     answ = readstr(data);
  2548.   };
  2549.  
  2550.  
  2551.  
  2552.   fclose(Fconfig);
  2553. };
  2554.