esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% MENU.MAC 
#%NAME% 
# General menu handling macros.
#
#%CATEGORY% Tools
#
#%DESCRIPTION% Provides macros developpers with a set of functions useful to create and handle a menu. 
#%OVERVIEW%  
#%DL%
#%DT% menu %DD% calls the user menu.
#%DT% menuoptskip - menuoptval - menuoptbutton - menuoptlist %DD% define an option.
#%DT% menuoptgroupselect1 %DD% define several options formated in a particular way.
#%DT% menuvargetv - menuvaryeno - menuvartogg - menuvarbitw - menuvarlist - menuvardynl menuvar2lis %DD% define the way last defined option is to be assigned.
#%DT% menuaction %DD% associates an action to the last defined option.
#%DT% menuerror %DD% could be an action that would print a message after menu execution.
#%DT% menuprint menuprb menuprr menupru%DD% simply prints information in the menu body without considering it as an option.
#%DT% menuitemchk - menuexecchk %DD% help in debugging. 
#%XDL%
#%EXAMPLE%
#This %B%menuexample%B% macro is in that file. You can execute it. 
#%PRE%
#def menuexample 
#  menu("\n  EXAMPLE","menu_example_display")
#
#def menu_example_display 
# global MENU_EX
#
# menuoptval  (0,"\n","ARBITRARY VALUE",MENU_EX[0])
# 	menuvargetv ("MENU_EX[0]")
# menuoptval(0,"\n","TOGGLE 1/0",MENU_EX[1]?"NO":"YES")
# 	menuvartogg ("MENU_EX[1]",25829) 
# menuoptval(0,"\n","TOGGLE bit no 2",MENU_EX[2]&4?"YES":"NO")
# 	menuvarbitw ("MENU_EX[2]",4)
# menuoptval(0,"\n","LIST SELECTION",MENU_EX[3])
# 	menuvarlist("MENU_EX[3]","CANNES  GRENOBLE  VALENCE",MENU_EX[3]) 
# print MENU_SEP
# menubutton(20,"\n","GO","G")
# 	menuaction ("print \"Going ...\";sleep(3)")
#
#%PRE%
#%END%

#---------------------------------------------------------------------- EXAMPLE
def menuexample '
menu("\n  EXAMPLE","menu_example_display")
'

def menu_example_display '{
  global MENU_EX

  menuoptval  (0,"\n","ARBITRARY VALUE",MENU_EX[0])
  menuvargetv ("MENU_EX[0]")

  menuoptval(0,"\n","TOGGLE 1/0",MENU_EX[1]?"NO":"YES")
  menuvartogg ("MENU_EX[1]",25829) 

  menuoptval(0,"\n","TOGGLE bit no 2",MENU_EX[2]&4?"YES":"NO")
  menuvarbitw ("MENU_EX[2]",4)

  menuoptval(0,"\n","LIST SELECTION",MENU_EX[3])
  menuvarlist("MENU_EX[3]","CANNES  GRENOBLE  VALENCE",MENU_EX[3]) 

  print MENU_SEP
  menuoptbutton(20,"\n","GO","G")
  menuaction ("print \"Going ...\";sleep(3)")
}'


#-------------------------------------------------------------- MENU DEFINITION

#%UU% (no_of_option_to_skip)
#%MDESC% Allows to define temporarily unused options.
def menuoptskip (no) '{
  menu_initoption (no)
}'


#%UU% (format,end,"text",value,"key")
#%MDESC% Defines an option which display is a description text and the corresponding value. %BR%
#%B%format%B% is the field-width for printf("%s") function. %B%end%B% is printed after the %B%value%B%, while %B%text%B% is printed before. %B%key%B% is eventually the highlighted letter (or string) to type, taken or not from %B%text%B%, for selecting that option. If there is no key specified, the option number is used instead.
def menuoptval (fmt,end,txt,val,key) '{
  menu_initoption(1)
  if (key!="") MENU_OPTION[key] =MENU_OPT
  else MENU_OPTION[MENU_OPT]=MENU_OPT
  MENU_Q[MENU_OPT]=txt
  if (key!="") menu_pr_key(fmt,end,key,txt,val)
  else menu_pr_opt(fmt,end,MENU_OPT,txt,val)
}'

# flag
# 0 : Highlights key or option num
# 1 : Highlights txt matching arg1

#%UU% (format,end,"text","key",flag,arg1,arg2) 
#%MDESC% Defines an option which is displayed as a button. %BR%
#%B%format%B% is the field-width for printf("%s",text) function. %B%end%B% is printed after the %B%text%B%. %B%key%B% is eventually the highlighted letter (or string) to type, taken or not from %B%text%B%, for activating that button. If there is no key specified, the option number is used instead.
#%BR%%B%flag%B%, %B%arg2%B% and %B%arg2%B% are not used at the moment. The idea is the Highlight the button under certain conditions defined through those 3 inputs.
def menuoptbutton (fmt,end,txt,key,flag,arg1,arg2) '{
  menu_initoption(1)
  if (key!="") MENU_OPTION[key] =MENU_OPT
  else MENU_OPTION[MENU_OPT]=MENU_OPT
  MENU_Q[MENU_OPT]=txt
  if (key!="") menu_pr_button(fmt,end,key,txt,flag,arg1,arg2)
  else menu_pr_button(fmt,end,MENU_OPT,txt,flag,arg1,arg2)
}'

#%UU% (format, end, "text", array, size, key, flag) 
#%MDESC% Defines an option which displays a description text and the content of a single row array as value. %BR%
#%B%format%B% is the field-width for printf("%s") function. %B%end%B% is printed after the %B%array%B% content, while %B%text%B% is printed before. %B%size%B% is of the size of the %B%array%B%. %B%key%B% is eventually the highlighted letter (or string) to type, taken or not from %B%text%B%, for selecting that option. If there is no key specified, the option number is used instead. %B%flag%B% is 0 or 1, distinguishes between 2 flavours of display.

def menuoptlist (fmt, end, text, selarr, size, key, flag) '{
  local str

  for (str="",i=0;i<size;i++) str = sprintf("%s%s, ",str,selarr[i])
  str = substr(str,1,length(str)-2)
  if (flag) {
    menuoptbutton (fmt,0,text,key)
    MENU_Q[MENU_OPT]=text
    menuprint  (0,end,"",str)
  }
  else menuoptval(fmt,end,text,str,key)
}'


#%UU% (format,end,"text",list,current,size,"variablename",flag) 
#%MDESC% Defines as option each element of the %B%list%B%, held in an \"old fashion array\", and display them all, with the %B%current%B% selected one printed first, just after the %B%text%B%. Neither assignement nor actions can be associated with such option, because it is fixed internally. The action beyond it is the selection of one current item. This is usually the header of a menu that is common to several devices...
#%B%format%B% is the field-width for printf("%s",text) function. %B%end%B% is printed after each listed item, except 1st one. %B%size%B% is the size of the array containing the %B%list%B%. %B%variablenam%B% is the name of the global that holds %B%current%B% index value. %B%flag%B% distinguishes between various display flavours (0,1,2,4). 

def menuoptgroupselect1 (fmt,end,text,arr,curr,size,currvarname,flag) '{
  local len

  len=length(text)
  if (fmt>len) len=fmt
  len += length(sprintf(" <%s> , others: ",arr[curr]))

  menuprint(fmt,0,text,arr[curr]); 
  printf(", others: ")
  for (i=0;i<size;i++) {
    if (i!=curr) {
      if (flag&1) menuoptbutton (0,end,arr[i])
      else if (flag&2) menuoptbutton (0,end,arr[i],arr[i])
      else menuoptval (0,end,"",arr[i])
      if (index(end,"\n")) printf(sprintf("%%%ds",len),"")
    }
    else menuoptskip(1)
    menuaction(sprintf("%s=%d;",currvarname,i))
  }
  if (!(flag&4)) printf ("\n")
}'


#%UU% ("action")
#%MDESC% Associates the %B%action%B% to the last option defined. It is to be executed after the option has been selected and eventually assigned a new value by the user.
def menuaction (action) '{

if (action!="") MENU_ACTION[MENU_OPT]=action
else MENU_ACTION[MENU_OPT]=""
}'


#%UU% ("message")
#%MDESC% Stores a message in the error buffer that is flushed after each option execution. Could be inserted in any menu action.
def menuerror (msg) '{ 
  MENU_ERRBUF=sprintf("%s\n%s",MENU_ERRBUF,msg)
}'


#%UU% ("message")
#%MDESC% Stores a message in the warning buffer that is flushed after each option execution. Could be inserted in any menu action.
def menuwarning (msg) '{ 
  MENU_WARBUF=sprintf("%s\n%s",MENU_WARBUF,msg)
}'


# TYPES
# 0,1 reserved
# 2 getval a variable
# 4 yesno a variable  
# 8 toggle a variable between two values 
# 16 toggle a variable bitwise a value
# 32 assign a variable to value out of a list 
# 64 assign a variable to value out of a modifiable list

#%UU% ("varname","question")
#%MDESC% Associates to the last defined option the assignement of the global %B%varname%B% through getval() function. %B%question%B% is eventually the text displayed when prompting for the new value. Otherwise, the option description text is used.
def menuvargetv (varname,question) '{
  MENU_TYPE[MENU_OPT]=2
  MENU_VARNAME[MENU_OPT]=varname
  if (length(question)) MENU_Q[MENU_OPT]=question
}'

#%UU% ("varname","question")
#%MDESC% Associates to the last defined option the assignement of the global %B%varname%B% through yesno() function. %B%question%B% is eventually the text displayed when prompting the user. Otherwise, the option description text is used.
def menuvaryeno (varname,question) '{
  MENU_TYPE[MENU_OPT]=4
  MENU_VARNAME[MENU_OPT]=varname
  if (length(question)) MENU_Q[MENU_OPT]=question
}'
#%UU% ("varname",val1,val2) 
#%MDESC% Associates to the last defined option the assignement of the global %B%varname%B% by toggling itself. %B%val1%B% and %B%val2%B% are eventually the 2 value that the global can take. If none are specified, there are assumed to be 1 and 0.
def menuvartogg (varname,val1,val2) '{
  MENU_TYPE[MENU_OPT]=8
  MENU_VARNAME[MENU_OPT]=varname
  if (val2!=val1) {
    MENU_TOG0[MENU_OPT] = val1
    MENU_TOG1[MENU_OPT] = val2
  } else {
    MENU_TOG0[MENU_OPT] = 0
    MENU_TOG1[MENU_OPT] = 1
  }
}'

#%UU% ("varname",bitmask)
#%MDESC% Associates to the last defined option the assignement of the global %B%varname%B% by bitwise toggling itself. %B%bitmask%B% is the mask used in the bitwise operation.
def menuvarbitw (varname,bitmask) '{
  MENU_TYPE[MENU_OPT]=16
  MENU_VARNAME[MENU_OPT]=varname
  MENU_TOG0[MENU_OPT] = bitmask
}'

#%UU% ("varname","stringlist") 
#%MDESC% Associates to the last defined option the assignement of the global %B%varname%B% by one of the elements of %B%stringlist%B%, 2 spaces-separated. 
def menuvarlist (varname,stringlist) '{
  MENU_TYPE[MENU_OPT]=32
  MENU_VARNAME[MENU_OPT]=varname
  MENU_Q[MENU_OPT]=sprintf("%s:  %s",MENU_Q[MENU_OPT],stringlist)
}'

#%UU% ("currindex_name","list_arrayname","arraysize_varname","delmacro","addmacro")
#%MDESC% Associates to the last defined option the assignement of the global %B%currindex_name%B% to the selected item index through %B%list_arrayname%B%. This array-list is dynamic, what means it is also possible to change its content. The macros%B% delmacro%B% and %B%addmacro%B% are called respectively, after the delete request has been done, passed the index and size as arguments (prior to deletion, starting from 0), and after the addition request has been done, passed the new index as argument). 
def menuvardynl (currindexname,listarrayname,sizevarname,macadd,macdel) '{
  MENU_TYPE[MENU_OPT]=64
  MENU_VARNAME[MENU_OPT]=currindexname
  MENU_TOG0[MENU_OPT] = listarrayname
  MENU_TOG1[MENU_OPT] = sizevarname
  MENU_VARNAM2[MENU_OPT] = sprintf("%s&%s",macdel,macadd)
}'

#%UU% ("arrayname","arraysizename","refarrayname","refarraysizename")
#%MDESC% Associates to the last defined option the assignement of the globals %B%arrayname%B% and %B%arraysizename%B% of the selected items out of the %B%refarrayname%B% reference array which size is also given as%B% refarraysizename%B%.
def menuvar2lis (arrayname,sizename,refarrname,refarrszname) '{
  MENU_TYPE[MENU_OPT]=128
  MENU_VARNAME[MENU_OPT]= arrayname
  MENU_VARNAM2[MENU_OPT]= sizename
  MENU_TOG0[MENU_OPT]   = refarrname
  MENU_TOG1[MENU_OPT]   = refarrszname
}'

#%IU% (no_of_option_fields_to_prepare) 
#%MDESC% Increments option index and resets the related information.
def menu_initoption (no) '{
global MENU_OPT

for (iii=0;iii<no;iii++) {
  MENU_OPT++
  MENU_Q[MENU_OPT]=""
  MENU_ACTION[MENU_OPT]=""
  MENU_TYPE[MENU_OPT]=0
#  MENU_OPTION[MENU_OPT]=0
  MENU_VARNAME[MENU_OPT]=""
  MENU_VARNAM2[MENU_OPT]=""
  MENU_TOG0[MENU_OPT]=""
  MENU_TOG1[MENU_OPT]=""
}
}'

#%UU% (globalvar,lineoffset,linenum,columnoffset,columnnum,arg0,arg1,arg2) 
#%MDESC% Records the information in a way that %B%menutable%B% display command understands.%BR% What consists of assigning the array %B%globalvar%B% suitably with the information held in %B%arg0%B%, %B%arg1%B% and %B%arg2%B% parameters, and at the position defined via %B%lineoffset%B%%B%, linenum%B%%B%, columnoffset%B% and %B%columnnum%B% parameters. %BR% 
#%DL%%B%arg0%B% can be : 
#%DT% zero
#%DD% then, the %B%globalvar%B% array specified area would be filled with %B%arg1%B%+linenum+colnum, eventually multiplied by %B%arg2%B%.
#%DT% a non zero valued symbol
#%DD% then, %B%arg1%B% and %B%arg2%B% must not be specified and the globalvar area is filled with that non zero value. 
#%DT% an array symbol name
#%DD% then, %B%arg1%B% and %B%arg2%B% are the line offset, and eventually the column offset of that array.
#%XDL%
#initialiases globalvar as an array gv[0]=0
#even if content is unknown, think to reserve some place by calling it. 
def menutabdef (tab,loff,lsz,coff,csz,what,wloff,wcoff) '{
local ll cc

lsz=lsz?lsz:1
csz=csz?csz:1
for (ll=0;ll<lsz;ll++) 
  for (cc=0;cc<csz;cc++) {
    if (whatis("what")>0x40100004 || 0!=what) {
      if (length(wloff)) {
        if (length(wcoff)) \ 
          tab[sprintf("%d@@%d",ll+loff,cc+coff)] = what [wloff+ll][wcoff+cc]
        else tab[sprintf("%d@@%d",ll+loff,cc+coff)] = what [wloff+ll]
      } 
      else tab[sprintf("%d@@%d",ll+loff,cc+coff)] = what
    }
    else if (wcoff) tab[sprintf("%d@@%d",ll+loff,cc+coff)] = wcoff*(wloff+ll)
    else tab[sprintf("%d@@%d",ll+loff,cc+coff)] = wloff+ll+cc
  }
}'

#----------------------------------------------------------------- MENU DISPLAY
#%UU% (format,end,"text",value)
#%MDESC% Prints %B%text%B% and %B%value%B%, like %B%menuoptval%B%, but without considering it as an option.
def menuprint (fmt,end,txt,val) '{
  menu_pr_opt(fmt,end,0,txt,val)
}'

def menuprintlist (fmt, end, text, selarr, size) '{
  local str

  for (str="",i=0;i<size;i++) str = sprintf("%s%s, ",str,selarr[i])
  str = substr(str,1,length(str)-2)
  menu_pr_opt(fmt,end,0,text,str)
}'

#%UU% ("text")
#%MDESC% Simply prints %B%text%B% in bold characters.
def menuprb (txt) '{
  printf("%s%s%s",MENU_ONB,txt,MENU_OFS)
}'
#%UU% ("text")
#%MDESC% Simply prints %B%text%B% in reversed video.
def menuprr (txt) '{
  printf("%s%s%s",MENU_ONR,txt,MENU_OFS)
}'
#%UU% ("text")
#%MDESC% Simply prints %B%text%B% in underligned characters.
def menupru (txt) '{
  printf("%s%s%s",MENU_ONU,txt,MENU_OFS)
}'
#%UU% ("text")
#%MDESC% Simply prints %B%text%B% in bold and underligned characters.
def menuprbu (txt) '{
  printf("%s%s%s",MENU_BU,txt,MENU_OFS)
}'

#%IU% (fmt,end,key,text,flag,arg1,arg2) 
#%MDESC% Prints button style option.
def menu_pr_button (fmt,end,key,text,flag,arg1,arg2) '{
local format txt1 txt2 sep keylen sig

if (fmt<0) sig  = "-"
else sig=""
fmt = fabs(fmt)

if ("0"==end ) end  = ""
if ("0"==text) {
  sep = text = txt1 = txt2 = ""
} else {
  keylen = length(key)
  sep = index(text,key)
  txt1=substr(text,0,sep-1)
  txt2=substr(text,sep+keylen)
}

if (sep==0) {
  text = sprintf("%s%s%s %s",MENU_ONB,key,MENU_OFS,text)
  if (fmt) fmt+=length(MENU_ONB)+length(MENU_OFS)
} else {
  text = sprintf("%s%s%s%s%s",txt1,MENU_BU,key,MENU_OFS,txt2)
  if (fmt) fmt+=length(MENU_BU)+length(MENU_OFS)
}
format = sprintf("%%%s%ds%s",sig,fmt,end)
printf(format,text)

LENG[MENU_OPT]=length(sprintf(format,text))
}'


#%IU% (fmt,end,opt,text,value) 
#%MDESC% Prints basic style option, or any information.
def menu_pr_opt (fmt,end,opt,text,value) '{
local format key sig

if (fmt<0) sig  = "-"
else sig=""
fmt = fabs(fmt)

if ("0"==text) text = ""
if ("0"==end ) end  = ""
if ("0"==opt) {
  if (fmt) fmt -= (4 + length(value) + length(end))
  format = sprintf("%%%s%ds <%%s%%s%%s> %s",sig,fmt,end)
  printf(format,text,MENU_ONB,value,MENU_OFS)
} else {
  if (fmt) fmt -= (5 + length(value) + length(end) + ((length(opt)>2)?length(opt):2))
  format = sprintf("%%s%%2s%%s %%%s%ds <%%s%%s%%s> %s",sig,fmt,end)
  printf(format,MENU_ONB,opt,MENU_OFS,text,MENU_ONB,value,MENU_OFS)
}

LENG[MENU_OPT]=length(sprintf(format,MENU_ONB,opt,MENU_OFS,text,MENU_ONB,value,MENU_OFS))
}'

#%IU% (fmt,end,key,text,value) 
#%MDESC% Prints basic style option, but with a key.
def menu_pr_key (fmt,end,key,text,value) '{

local format txt1 txt2 sep keylen sig 

if (fmt<0) sig  = "-"
else sig=""
fmt = fabs(fmt)

if ("0"==end ) end  = ""

if ("0"==text) {
  sep = text = txt1 = txt2 = ""
} else {
  keylen = length(key)
  sep = index(text,key)
  txt1=substr(text,0,sep-1)
  txt2=substr(text,sep+keylen)
}
if (sep==0) {
  if (fmt) fmt -= (7 + length(value) + length(end) + ((length(key)>2)?length(key):2))

  format = sprintf("- %%s%%2s%%s %%%s%ds <%%s%%s%%s> %s",sig,fmt,end)
  printf(format,MENU_ONB,key,MENU_OFS,text,MENU_ONB,value,MENU_OFS)
  LENG[MENU_OPT]=length(sprintf(format,"",key,"",text,"",value,""))
} else {
  if (fmt) {
    fmt += length(MENU_OFS) + length(MENU_BU)
    fmt -= (4 + length(value) + length(end))
  }
  format = sprintf("%%%s%ds <%%s%%s%%s> %s",sig,fmt,end)
  text = sprintf("%s%s%s%s%s",txt1,MENU_BU,key,MENU_OFS,txt2)
  printf(format,text,MENU_ONB,value,MENU_OFS)   
  LENG[MENU_OPT]=length(sprintf(format,text,"",value,""))
}

}'

#%UU% 
#%MDESC% Prints 1 line through the screen.
def menusep 'print MENU_SEP'

#%UU% (globalvar,lines,cols,separator,flag)
#%MDESC% Displays the information held in %B%globalvar%B% array in a table format. %BR%The %B%globalvar%B% must be indexed by a string of the following form :"line@@col", or "col@@line".( This is what %B%menutabdef%B% macro does automatically ). %B%lines%B% and %B%cols%B% simply gives the whole table size. %B%separator%B% is a string printed between columns. 
#flag distinguishes between several formats described here:
#%UL%  
#%LI% flag 0 : first line is the header separated by a line from the rest
#%LI% flag&1 : twists lines and cols.
#%LI% flag&2 : expands the table to use all the screen columns (80).
#%LI% flag&4 : left justifies data.
#%LI% flag&8 : no header. separates all lines by a line
#%XUL%
def menutable (tab,lin,col,sep,flag) '{
local csz c l left
local screen sdiv sklst num

if (flag&4) left="-"
else left = ""

for (c=0;c<col;c++) {
  for (l=0;l<lin;l++) {
    if (flag&1) xx = sprintf("%d@@%d",c,l)
    else xx = sprintf("%d@@%d",l,c)
    if (csz[c]<length(tab[xx])) csz[c] = length(tab[xx]); 
  }
}

if (flag&2) {
  screen = 80 ; sklst = ""; num = col
  for (c=0;c<col && num>0;c++) {
    sdiv = int (screen/num) - length(sep) - col + num ;
    if (!index(sklst,c) && csz[c]>sdiv) {
      sklst = sprintf("%s %s",c,sklst)
      screen -= csz[c] ; num--
      c=-1;
    }
  }
  for (c=0;c<col;c++) if (!index(sklst,c)) csz[c]=sdiv
}
menusep
for (c=0;c<col;c++) {
  if (flag&1) xx = sprintf("%d@@0",c)
  else xx = sprintf("0@@%d",c)
  printf(sprintf("%%%s%ds%%s",left,csz[c]),tab[xx],sep)
}
menusep ; 
for (l=1;l<lin;l++) {
  for (c=0;c<col;c++) {
    if (flag&1) xx = sprintf("%d@@%d",c,l)
    else xx = sprintf("%d@@%d",l,c)
    printf(sprintf("%%%s%ds%%s",left,csz[c]),tab[xx],sep)
  }
  if (flag&8) { menusep }
  else printf("\n")
}
}'


#--------------------------------------------------------- CHARACTER PROCESSING

#%IU%
#%MDESC% Sets some characters processing up. (Bold,Underlined,...)
def menusetup '{

    global MENU_CTRLEN MENU_CLR MENU_OFS MENU_ONB MENU_ONR MENU_ONU
    global MENU_BU
    global MENU_ASCII MENU_SQUARE MENU_SEP

    MENU_ASCII="\101"
    MENU_SQUARE="\374"

    for (MENU_SEP=""; length(MENU_SEP)<80 ;MENU_SEP=sprintf("%s\260",MENU_SEP));

    MENU_SEP=sprintf("\n%s", MENU_SEP)


    if (TERM =="hpterm" || TERM == "hp") {
        MENU_CLR="&a0y0CJ"
        MENU_OFS=sprintf("%c&d@",27); MENU_ONB=sprintf("%c&d@",27) ;
        MENU_ONU=sprintf("%c&dD",27); MENU_ONR=sprintf("%c&dF",27) ;
        MENU_BU = sprintf("%s%s", MENU_ONU, MENU_ONB)
    }
    else{
        MENU_CLR=""
        MENU_OFS=sprintf("%c[m",27); MENU_ONB=sprintf("%c[1m",27) ;
        MENU_ONU=sprintf("%c[4m",27); MENU_ONR=sprintf("%c[7m",27) ;
        MENU_BU = sprintf("%s%s", MENU_ONU, MENU_ONB)
    }

    MENU_CTRLEN = 4
}'

#%UU%
#%MDESC% Turns bold character attribute on.
def menuchb 'print MENU_ONB'

#%UU%
#%MDESC% Turns all special character attributes off.
def menuchi 'print MENU_OFS'

#%UU%
#%MDESC% Turns reverse-video character attribute on.
def menuchr 'print MENU_ONR'

#%UU%
#%MDESC% Turns underligned character attribute on.
def menuchu 'print MENU_ONU'

#%UU%
#%MDESC% Prints ascii \374. (1 square).
def menuchsq 'printf("%s",MENU_SQUARE)'

#----------------------------------------------------------------- MENU HANDLER

#%UU% ("menutitle","displaymacro","updatemacro","exitmacro")
#%MDESC% Calls the menu.  %BR%
# %B%displaymacro%B% is the name of the macro where the menu has been defined using this set of macros. %B%updatemacro%B% is the name of the macro that eventually reads in global settings to be displayed in the menu; it is run before the %B%displaymacro%B%. %B%exitmacro%B% is executed when exiting the menu loop. Put all what you want to do after the menu has been executed here. The menu must be the only command on its expansion level. 
def menu (title,displaymacro,updatemacro,exitmacro) '{
  cdef ("user_cleanup2","cdef (\"\",\"\",\"menus\",\"delete\")","menus",0)
  cdef ("menu_update",sprintf("%s\n",updatemacro),"menus",0)
  cdef ("menu_display",sprintf("%s\n",displaymacro),"menus",0)
  cdef ("menu_exit",sprintf("%s\n",exitmacro),"menus",0)
  menu_doit (title)  
}
'


#%IU% (title)
#%MDESC% The menu manager !
def menu_doit (title) '{
  global MENU_OPT MENU_ERRBUF MENU_WARBUF
  global MENU_Q MENU_ACTION MENU_TYPE MENU_OPTION MENU_VARNAME MENU_VARNAM2 MENU_TOG0 MENU_TOG1
  local asw format

  cdef ("_menu_action","","menus",0)
  cdef ("_menu_back","","menus",0)

  format = sprintf("%%s%%s%%%ds%%s%%s",0)
  printf(format,MENU_CLR,MENU_ONB,title,MENU_OFS,"\n")
  printf(format,"",MENU_ONB,MENU_SEP,MENU_OFS,"\n")

  MENU_OPT = 0
  for (i in MENU_OPTION) delete MENU_OPTION[i]  
  menu_update
  menu_display 
  printf(format,"",MENU_ONB,MENU_SEP,MENU_OFS,"\n")
  menu_err_print
  menu_war_print
  if ("0"!=(asw = getval ("Enter highlighted key or 0 to exit",0))) {
    printf(format,"",MENU_ONB,MENU_SEP,MENU_OFS,"\n")
    cdef ("_menu_action","","","delete")
    menu_exec (asw)
    cdef ("_menu_back",sprintf("menu_doit(\"%s\")\n",title),"menus",0)
  } else {
    menusep
#    menu_exit
  cdef ("_menu_back","menu_exit;cdef(\"\",\"\",\"menus\",\"delete\");","menus")
  }
}
_menu_action
_menu_back
'

#%IU%
#%MDESC% Flushes error buffer.
def menu_err_print '{
  if (MENU_ERRBUF!="") {
    beep
    printf( "%sErrors occured:%s %s",MENU_ONU,MENU_OFS,MENU_ERRBUF)
    menusep
  }
  MENU_ERRBUF=""
}'


#%IU%
#%MDESC% Flushes warnings buffer.
def menu_war_print '{
  if (MENU_WARBUF!="") {
    beep
    printf( "%sWARNING:%s %s",MENU_ONU,MENU_OFS,MENU_WARBUF)
    menusep
  }
  MENU_WARBUF=""
}'


#%IU% (hkey)
#%MDESC% Sorts out what to do out of the selected option.
def menu_exec (hkey) '{
local option type question action action1 var tog tog1

option   = MENU_OPTION[hkey]
question = action = action1 = ""
 
if (option && option<=MENU_OPT) {
  type  =MENU_TYPE[option]
  action=sprintf("%s\n",MENU_ACTION[option])
  question=MENU_Q[option]
  var=MENU_VARNAME[option];var1=MENU_VARNAM2[option]
  tog=MENU_TOG0[option];tog1=MENU_TOG1[option]

  if ( 2&type) action1 = sprintf("%s=getval(\"%s\",%s)",var,question,var) 
  if ( 4&type) action1 = sprintf("%s=yesno(\"%s\",%s)",var,question,var)
  if ( 8&type) action1 = sprintf("%s=(%s==\"%s\")?\"%s\":\"%s\"",var,var,tog,tog1,tog)
  if (16&type) action1 = sprintf("%s=(%s&%d)?(%s&~%d):(%s|%d)",                                                 var,var,tog,var,tog,var,tog)
  if (32&type) {
    local idx que lis
    idx = index(question,": ")
    que = substr(question,1,idx-1)
    lis = substr(question,idx+3)
    action1 =  sprintf("print MENU_ONB,\"%s\",MENU_OFS;%s=menu_list (\"%s\",%s)",que,var,lis,var)
  }
  if (64&type) {
    local mdel madd
    sscanf(var1,"%[^&]& %s",mdel,madd)
    if (mdel!="") cdef ("_menu_dynlist_del",sprintf("%s \$1 \$2;",mdel),"menus",0)
    else cdef ("_menu_dynlist_del","\#\$*\n","menus",0)
    if (madd!="") cdef ("_menu_dynlist_add",sprintf("%s \$1;",madd),"menus",0)
    else cdef ("_menu_dynlist_add","\#\$*\n","menus",0)
    action1 =  sprintf("tty_move(0,0);tty_cntl(\"ce\");print MENU_ONB,\"%s\",MENU_OFS; print MENU_SEP;%s=menu_dynlist (%s,%s,%s); sscanf(%s,\"%%d %%d\",%s,%s);",question,var,tog,tog1,var,var,var,tog1)
  }
  if (128&type) {
    action1 = sprintf("print MENU_CLR;print MENU_ONB,\"%s\",MENU_OFS; print MENU_SEP; %s=menu_2lists(%s,%s,%s,%s); ",question,var1,var,var1,tog,tog1)
  }
} else MENU_ERRBUF=sprintf("%s %s unknown option;",MENU_ERRBUF,hkey)

action=sprintf("%s\n%s\n",action1,action)
cdef("_menu_action",action,"menus",0)
}'

#%IU%  (elem,nelem,init) 
#%MDESC% Manages value selection through a dynamic list of values. Returns the selected element as the corresponding index to the array elem.
def menu_dynlist (elem,nelem,init) '{
  local i  sel ret
  
  for (sel=1;sel;sel = input("\n 0 : quit\n\n ---> ")) { 
    if (sel<0 && fabs(sel)<=nelem) {
      sel = fabs(sel)
      if (yesno("Confirm",1)) {
        _menu_dynlist_del sel-1 nelem
        elem[sel-1] = elem[--nelem]
        elem[nelem] = 0
        if (sel>nelem) sel = 1
      }
    }
    else if (sel>nelem) {
      if (!nelem) {
        tty_cntl("cd")
        tty_move(0,3)
        tty_cntl("cd")
      }
      elem[nelem++] = getval("new item","");
      sel=nelem
      _menu_dynlist_add sel-1
    }
    
    ret=ret?sel:init+1
    tty_cntl("cd")
    tty_move(0,3,"Choose through the following:")
    tty_cntl("cd")
    tty_move(0,5)
    print "-<num> : remove one item from that list"
    print "\r",nelem+1,":","add new item to that list\n\n"
    for (i=nelem;i>0;i--) {
      if (i==ret) print MENU_ONB,i,":",elem[i-1],MENU_OFS
      else print "\r",i,":",elem[i-1]
    }
  }
ret=sprintf("%d %d",ret-1, nelem)
return (ret)
}'

#%IU% (list,init)
#%MDESC% Manages selection through a fixed list of values. Returns the value selected.
def menu_list (list,init) '{

local i nelem elem sel 
print "\n Choose through the following:\n\n"
nelem = split(list,elem,"  ")
for (i=nelem;i>0;i--) {
  if (elem[i-1]==init) print MENU_ONB,i,":",elem[i-1],MENU_OFS
  else print "\r",i,":",elem[i-1]
}
sel = input("\n---> ")
if (sel>0&&sel<=nelem) return (elem[sel-1])
else return (init)
}'


#%IU% (list,sz,list0,sz0)
#%MDESC% Manages the selection of certain elements held in an array, to be held in another array. Returns the size (sz) of the second array.
def menu_2lists (list,sz,list0,sz0) '{

  local sel ttyx i j text
  
  for (sel="";sel!="q";sel = getval(sprintf("enter element to move or %sq%suit\n\n ---> ",MENU_ONB,MENU_OFS),"q")) { 
    ttyx[0]=ttyx[1]=length("SELECTION: ")
    tty_move(0,5,"SELECTION: ");tty_cntl("ce")
    tty_move(0,7,"    OTHER: ");tty_cntl("ce")
    for (i=0;i<sz0;i++) {
      text = sprintf("<%s%s%s>",MENU_ONB,list0[i],MENU_OFS)
      for (j=0;j<sz;j++) {
         if (list0[i]==list[j]) break
      }
      if (sel == list0[i]) {
        if (j==sz) {
          list[sz++]=sel
        } else {
          list[j]=list[--sz]
          j=sz
        }
      }
      if (j==sz) {
        tty_move(ttyx[0],7,text) 
        ttyx[0]+=length(text)-2
      } else {
        tty_move(ttyx[1],5,text); 
        ttyx[1]+=length(text)-2
      }
    }
    tty_move(0,11);tty_cntl("ce");tty_move(0,9)
  }

return (sz)
}'


#----------------------------------------------------------------- MENU TESTING

#%UU% [option_number]
#%MDESC% FOR DEBUGGING: Describes last run menu regarding internal registers.
def menuitems '{
local a b
a=1;b=MENU_OPT
if ($1) {
   a=$1
   if ($2) b=$2
   else b=$1
}
print MENU_SEP
for (i=a;i<=b;i++) {
  p "option number	",i
  p "type		", MENU_TYPE[i]&2?"getval":(MENU_TYPE[i]&4?"yesno":(MENU_TYPE[i]&8?"toggle":(MENU_TYPE[i]&16?"bitwise":(MENU_TYPE[i]&32?"list":(MENU_TYPE[i]&64?"dynamic list":(MENU_TYPE[i]&128?"double list":"single action"))))))

if (MENU_TYPE[i]&(2|4|8|16|32|64)) p "variable		",MENU_VARNAME[i]
if (MENU_TYPE[i]&(2|4))  print "question:",question
if (MENU_TYPE[i]&(8)) print "togs    :",tog,tog1
if (MENU_TYPE[i]&(16)) print "mask    :",tog
if (MENU_TYPE[i]&(32)) print "question:",que,"\nlist    :",lis
if (MENU_TYPE[i]&(64)) print "list    :",tog,"size",tog1,"\nmacros  :",madd,mdel
if (MENU_TYPE[i]&(128)) print "list    :",var,"sz",var1,"\nrefer   :",tog,"sz",tog1
print "action  :",action
input("return to execute it")


MENU_VARNAM2[i]
MENU_Q[i]
MENU_TOG0[i]
MENU_TOG1[i]
MENU_ACTION[i]
  input("Return")
}
}'

#%UU% [option_number]
#%MDESC% FOR DEBUGGING: Dumps last run menu related internal registers.
def menuitemchk '{
local a b
a=1;b=MENU_OPT
if ($1) {
   a=$1
   if ($2) b=$2
   else b=$1
}
print MENU_SEP
for (i=a;i<=b;i++) {
  p "MENU_OPTION",i# MENU_OPTION[i]
  p "MENU_TYPE", MENU_TYPE[i]
  p "MENU_VARNAME", MENU_VARNAME[i]
  p "MENU_VARNAM2", MENU_VARNAM2[i]
  p "MENU_Q",MENU_Q[i]
  p "MENU_TOG0", MENU_TOG0[i]
  p "MENU_TOG1",MENU_TOG1[i]
  p "MENU_ACTION", MENU_ACTION[i]
  input("Return")
}
}'



#%UU%
#%MDESC% FOR DEBUGGING: Toggles a mode where menu registers are dumped at option selection, prior to execution.
def menuexecchk '{
global MENUECHK
if (MENUECHK && !unix("test -r /tmp/menu_exec")) {
  qdo /tmp/menu_exec
  MENUECHK=0
  exit
} 
MENUECHK=1
savmac menu_exec /tmp/menu_exec
rdef menu_exec (hkey) \'{
local option type question action action1 var tog tog1
local idx que lis
local mdel madd

option   = MENU_OPTION[hkey]
question = action = action1 = ""
 
if (option && option<=MENU_OPT) {
  type  =MENU_TYPE[option]
  action=sprintf("%s\n",MENU_ACTION[option])
  question=MENU_Q[option]
  var=MENU_VARNAME[option];var1=MENU_VARNAM2[option]
  tog=MENU_TOG0[option];tog1=MENU_TOG1[option]

  if ( 2&type) action1 = sprintf("%s=getval(\"%s\",%s)",var,question,var) 
  if ( 4&type) action1 = sprintf("%s=yesno(\"%s\",%s)",var,question,var)
  if ( 8&type) action1 = sprintf("%s=(%s==\"%s\")?\"%s\":\"%s\"",var,var,tog,tog1,tog)
  if (16&type) action1 = sprintf("%s=(%s&%d)?(%s&~%d):(%s|%d)",                                                 var,var,tog,var,tog,var,tog)
  if (32&type) {
    idx = index(question,": ")
    que = substr(question,1,idx-1)
    lis = substr(question,idx+3)
    action1 =  sprintf("print MENU_ONB,\"%s\",MENU_OFS;%s=menu_list (\"%s\",%s)",que,var,lis,var)
  }
  if (64&type) {
    sscanf(var1,"%[^&]& %s",mdel,madd)
    if (mdel!="") cdef ("_menu_dynlist_del",sprintf("%s \$1 \$2;",mdel),"menus",0)
    else cdef ("_menu_dynlist_del","\#\$*\n","menus",0)
    if (madd!="") cdef ("_menu_dynlist_add",sprintf("%s \$1;",madd),"menus",0)
    else cdef ("_menu_dynlist_add","\#\$*\n","menus",0)
    action1 =  sprintf("tty_move(0,0);tty_cntl(\"ce\");print MENU_ONB,\"%s\",MENU_OFS; print MENU_SEP;%s=menu_dynlist (%s,%s,%s); sscanf(%s,\"%%d %%d\",%s,%s);",question,var,tog,tog1,var,var,var,tog1)
  }
  if (128&type) {
    action1 = sprintf("print MENU_CLR;print MENU_ONB,\"%s\",MENU_OFS; print MENU_SEP; %s=menu_2lists(%s,%s,%s,%s); ",question,var1,var,var1,tog,tog1)
  }
} else MENU_ERRBUF=sprintf("%s %s unknown option;",MENU_ERRBUF,hkey)

action=sprintf("%s\n%s\n",action1,action)
cdef("_menu_action",action,"menus",0)
if (option) {
  print "input was ",hkey,"i.e. option number",option
  print "type    :",type&2?"getval":(type&4?"yesno":(type&8?"toggle":(type&16?"bitwise":(type&32?"list":(type&64?"dynamic list":(type&128?"double list":"single action"))))))
if (type&(2|4|8|16|32|64)) print "variable:",var
if (type&(2|4))  print "question:",question
if (type&(8)) print "togs    :",tog,tog1
if (type&(16)) print "mask    :",tog
if (type&(32)) print "question:",que,"\nlist    :",lis
if (type&(64)) print "list    :",tog,"size",tog1,"\nmacros  :",madd,mdel
if (type&(128)) print "list    :",var,"sz",var1,"\nrefer   :",tog,"sz",tog1
print "action  :",action
input("return to execute it")
}
}\'
}
'

#---------------------------------------------------------------- MISCELLANEOUS

menusetup

#%MACROS%
#%IMACROS%
#%DEPENDENCIES%
#%PRE%
#  - The file %B%menu.mac%B% has to be read in 
#%PRE%
#%AUTHOR%
#  MENU.MAC - Marie-Claire LAGIER - 96/04/29
#%TOC%