
{  4/8/87  20:39   Menus}

!  The built-in function Set Up Menu expects the data to be given to it
!  as an array of items, each with its name and value in a record. Each
!  value is expected to be a list of lines.


%include "sm:consts.inc"
%include "sm:formats.inc"
%include "sm:utils.inc"
%include "inc:vtlib.imp"

%recordformat dataf(%string(19) name,%record(line80listf) val)
%recordformat menuf(%integer item,%string(19) name,%string(63) val)
%ownrecord(menuf)%array menu(0:250)

%owninteger cursorx,cursory
%owninteger datastart=20
%externalstring(31) helpfile="menuhelp"
%owninteger linelength=80, menudepth
%externalroutinespec view(%string(255) file,topic)
%owninteger wdepth=16, wmin, wmax
%routinespec write menu

%externalroutine screen message(%string(255) s,%string(15) mon)
%integer oldout
  oldout=outstream
  select output(0)
  gotoxy(0,wdepth+1)
  clear line
  print string(s)
  %monitor %if mon="mon"
  %stop %if mon="stop" %or mon="mon"
  gotoxy(cursorx,cursory)
  select output(oldout)
%end

%externalrecord(line80f)%map newline80
%record(line80f) pattern
%record(line80f)%name p
  p==new(pattern)
  p_next==nil; p_prev==nil
  p_line=""
  %result==p
%end

%routine h(%string(31) topic)
%string(255) x, y
  topic=x." ".y %while topic->x.("_").y
  view(helpfile,topic)
%end

%externalroutine start screen mode
{!  If Vax.}
{  define video(vttype)}
!
  select input(0); select output(0)
  set video mode(screen mode+special pad)
  set frame(wdepth+1,24,0,80)
  clear frame
  push frame
  set frame(0,wdepth,0,80)
  clear frame
  gotoxy(0,0)
  cursorx=0; cursory=0
  prompt("")
%end

%externalroutine stop screen mode
  clear frame
  set video mode(0)
%end

%externalroutine read screen line(%string(*)%name a)
%integer j,k
%string(255) u

  %on %event 15,0 %start
    read symbol(j) %until j=lf    ;!  To get rid of residual NL.
    h(menu(cursory)_name)
    write menu
  %finish

  prompt("")
  a=""
  cursorx=datastart
  gotoxy(cursorx,cursory-wmin)
  clear line
  %cycle
    read symbol(j)
    %exit %if j=lf %or j=enter
    %signal %event 15,0 %if j='?'
    screen message("Stopped at ".menu(cursory)_name,"stop") %if j=128+esc
    %continue %if j<=31 %or j>=128
    %if j=del %thenstart
!  This supposes that del has not been dealt with at the input.
      print symbol(sp)
      k=length(a)
      k=k-1; cursorx=cursorx-1
      k=0 %if k<0; cursorx=datastart %if cursorx<datastart
      length(a)=k
    %finishelsestart
!  This asssumes echo has been made.
      cursorx=cursorx+1
      a=a.tostring(j)
      %exit %if cursorx>linelength
    %finish
    gotoxy(cursorx,cursory-wmin)
  %repeat
  u=a; lower(u)
  cursorx=datastart; gotoxy(cursorx,cursory-wmin)
  clear line; print string(a)
  cursorx=0; gotoxy(cursorx,cursory-wmin)
%end

%externalroutine set up menu(%record(dataf)%arrayname data,
%integer mask)
%integer flag,i,j
%record(line80f)%name p
  menu(i)=0 %for i=0,1,31
!  Ensure that items 0 and 31 are available for escape.
  mask=mask!16_80000001
  menu(i)=0 %for i=0,1,250
  j=0
  %for i=0,1,31 %cycle
    %if mask&1=0 %then flag='n' %else flag='y'
    mask=mask>>1
    %continue %if flag='n'
!  Copy wanted item into menu.
    p==data(i)_val_head
    %if p==nil %thenstart
      menu(j)_item=i
      menu(j)_name=data(i)_name
      %if 0#i#31 %then menu(j)_val="*" %else menu(j)_val=""
      j=j+1
    %finishelsestart
      %while p##nil %cycle
        menu(j)_item=i
        menu(j)_name=data(i)_name
        menu(j)_val=p_line
        j=j+1
        p==p_next
      %repeat
    %finish
  %repeat
  menudepth=j-1
%end

%externalroutine write instruction(%string(255) s)
  swop frame
  gotoxy(0,wdepth+4)
  clear line
  gotoxy(0,wdepth+3)
  clear line
  gotoxy(0,wdepth+2)
  clear line
  print string(s)
  swop frame
  gotoxy(cursorx,cursory)
%end

%routine display line(%integer y)
  gotoxy(0,y-wmin)
  clear line
  print symbol(' ')
  print string(menu(y)_name)
  gotoxy(datastart,y-wmin)
  print string(menu(y)_val)
  gotoxy(0,y-wmin)
%end

!  This will not alter anything if the item is not in the menu.

%externalroutine write menu
%integer d, i
%string(255) s
!  Bring position of cursor within menu.
  %if cursorx<0 %then cursorx=0 %else %c
  %if cursorx>linelength %then cursorx=linelength
  %if cursory<0 %then cursory=0 %else %c
  %if cursory>menudepth %then cursory=menudepth
!  Adjust window depth to fit menu.
  d=wdepth; d=menudepth %if d>menudepth
!  Adjust window to fit position of cursor.
  wmin=cursory-d//2; wmin=0 %if wmin<0
  wmax=wmin+d; wmax=menudepth %if wmax>menudepth
  wmin=wmax-d; wmin=0 %if wmin<0
!  Display menu.
  display line(i) %for i=wmin,1,wmax
!  Write instructions.
  s="Move the cursor to the appropriate line.".snl. %c
    "Type ? and press <RETURN> for help. Press <Return> to alter.".snl. %c
    "Type in the value and press <RETURN> again.".snl. %c
    "Move the cursor off the screen to see more of the menu."
  write instruction(s)
!  Set cursor.
  gotoxy(cursorx,cursory-wmin)
%end
    
%externalintegerfn cursor depth
%integer j
  select input(0)
  prompt("")
  gotoxy(0,cursory-wmin)
  %cycle
    read symbol(j)
    %exit %if j=lf
    %if j=down %then cursory=cursory+1 %else %c
    %if j=up %then cursory=cursory-1 %else %c
    %if j&127=esc %then %signal 15,3 %elsestart
      %if j='?' %thenstart
        read symbol(j) %until j=lf    ;!  get rid of residual NL.
        h(menu(cursory)_name)
        write menu
      %finish
      %continue
    %finish
    %if cursory<0 %then cursory=0 %else %c
    %if cursory>menudepth %then cursory=menudepth
    %if wmin<=cursory<=wmax %then %c
    gotoxy(0,cursory-wmin) %else write menu
  %repeat
  cursorx=datastart
  gotoxy(cursorx,cursory-wmin)
  %result=menu(cursory)_item
%end


%endoffile

