{ NMENU.PAS - 8/25/96 by Brandon Sneed (Nivenh) }
{ Use it and abuse it and don't give me credit if you don't want too. }
{ example of use at the end !! }
unit nmenu;

interface

uses crt;

type
  menurec = record
            text : string[30]; { description }
            xpos,              { X coord }
            ypos : byte;       { Y coord }
            key  : char;       { hot key }
            end;

function domenu(var menu; numitems, start, highclr, loclr : byte) : byte;
  { the MENU param must be untyped since we'll be passing an array to it }
  {  menu = menu array constant                   }
  {  numitems = number of items in the menu array }
  {  start = which item should be highlighted by default? usually 1 }
  {  highclr = color to highlight with            }
  {  loclr = color to deselect with               }

implementation

function domenu(var menu; numitems, start, highclr, loclr : byte) : byte;
type
	{ Increase the size of this array for more than 25 menu items }
  menucast = array [1..25] of menurec;
var
  cnt : byte;
	choice : byte;
  getkey : char;
begin
  if start > numitems then start := 1;
  begin
  { draw the menu }
  for cnt := 1 to numitems do
    with menucast(menu)[cnt] do
    begin
    textattr := loclr;
    gotoxy(xpos, ypos);
    write(text);
    end;
  end;

  getkey := #255;
  choice := start;

  repeat
    if (choice <= numitems) and (choice > 0) then
    with menucast(menu)[choice] do
      begin
      textattr := highclr;
      gotoxy(xpos, ypos);
      write(text);
      textattr := loclr;

      if keypressed then
        getkey := readkey;
      { if a arrowkey, or any function type key is sent, a #0 always is sent
        first, and THEN the actual key value is sent. so, the first call to
        readkey will get #0, and the second will get the key we're looking
        for. }
      if getkey = #0 then
        begin
        getkey := readkey;
        case getkey of
          { up }
          #72 : if choice > 1 then
                begin
                textattr := loclr;
                gotoxy(xpos, ypos);
                write(text);
                dec(choice);
                end;
          { down }
          #80 : if choice < numitems then
                begin
                textattr := loclr;
                gotoxy(xpos, ypos);
                write(text);
                inc(choice);
                end;
          end;
        end;
      { if they hit ESC, set choice to 0 and exit }
      if getkey = #27 then choice := 0;
      { if they press a key, see if the key the pressed is a hotkey }
      getkey := upcase(getkey);
      if getkey in ['A'..'Z'] then
        begin
        for cnt := 1 to numitems do
          if getkey = menucast(menu)[cnt].key then
            begin
            choice := cnt;
            getkey := #13;
            end;
        end;
      end;

  until (getkey = #13) or (getkey = #27);
  domenu := choice;
end;

end.

{ ----------   DEMO PROGRAM ------------ }
{ 8/25/96 NMENU Example by Brandon Sneed }
program nmenuexample;

uses crt, nmenu;

const
	DummyMenu : Array [1..5] of MenuRec =
		((Text : ' Test 1 '; XPos : 1; YPos : 1; Key : '1'),
		 (Text : ' Test 2 '; XPos : 1; YPos : 2; Key : '2'),
		 (Text : ' Test 3 '; XPos : 1; YPos : 3; Key : '3'),
		 (Text : ' Test 4 '; XPos : 1; YPos : 4; Key : '4'),
		 (Text : ' Test 5 '; XPos : 1; YPos : 5; Key : '5'));
	{ the menu array can have as many options as you need.  just add them.
		be sure to change the 'numitems' value being passed to domenu }
var
	userpick : byte;

begin
	userpick := domenu( dummymenu,       { our menu const }
											5,               { total number of items in array }
											1,               { which item is first highlighted }
											$1F,             { highlight color (white! on blue) }
											$07);            { unhighlight color (white) }
	gotoxy(1, 7);
	writeln('User picked: '+DummyMenu[userpick].Text);
end.
