Subject: Table-driven ring menu
From: [email-masked] (Andrew Cilia)
Date: 30 Sep 1997 09:33:26 -0400
Newsgroups: comp.databases.informix

#ident	"@(#)menpro:Menu Processor"

   define
      men_array array[2,32] of record
         men_mncd like mndt_tabl.mndt_mncd,
         men_numb like mndt_tabl.mndt_numb,
         men_type like mndt_tabl.mndt_type,
         men_text char(37),
         men_path like mndt_tabl.mndt_path
      end record,
      men_start like mndt_tabl.mndt_mncd,
      dbe_xplan char(30)

main

   define
      f_user char(10)

   defer interrupt
   defer quit

   let f_user = fgl_getenv("LOGNAME")
   open window menwind at 2,2 with 22 rows, 78 columns       attribute
(border)
   let dbe_xplan=fgl_getenv("DBEXPLAIN")
   if dbe_xplan = "Y" then
      set explain on
   else
      set explain off
   end if
   let men_start=fgl_getenv("MENU")
   call show_menu(men_start)
end main

function show_menu(wrk_mncd)

   define
      wrk_mncd char(6),
      end_menu char(1),
      men_idx1 smallint,
      men_idx2 smallint,
      sav_indx smallint,
      f_date   date,
      wrk_mnnm like mnms_tabl.mnms_mnnm

   let end_menu = "N"
   while end_menu = "N"
   clear window menwind
   let f_date = today
   select mnms_mnnm into wrk_mnnm from mnms_tabl
   where mnms_tabl.mnms_mncd = wrk_mncd
   display wrk_mnnm, "           ", g_user.user_logn,
      f_date using "dd/mm/yyyy", " ", wrk_mncd
      at 03,01 attribute(reverse)

   call fgl_drawbox(1,78,20,1)
   display " " at 20,1
   display " " at 20,78
   menu men_array[1,1].men_mncd
      before menu
         declare men_curs cursor for
            select * from mndt_tabl
            where mndt_mncd = wrk_mncd
            for men_idx1 = 1 to 32
               let men_array[1,men_idx1].men_text = men_idx1 using "&&"
               initialize men_array[2,men_idx1].* to null
            end for
            let men_idx1 = 1
            let men_idx2 = 1
            foreach men_curs into
               men_array[2,men_idx2].men_mncd,
               men_array[2,men_idx2].men_numb,
               men_array[2,men_idx2].men_type,
               men_array[2,men_idx2].men_text,
               men_array[2,men_idx2].men_path
               if men_array[2,men_idx2].men_type = "P" or
                  men_array[2,men_idx2].men_type = "F" or
                  men_array[2,men_idx2].men_type = "M" then
                  let men_array[2,men_idx2].men_text =
                  men_idx1 using "&&", "-", men_array[2,men_idx2].men_text
                  let men_array[1,men_idx1].* = men_array[2,men_idx2].*
                  let men_idx1 = men_idx1 + 1
                  if men_array[2,men_idx2].men_type = "M" then
                     let men_array[2,men_idx2].men_text =
                     men_array[2,men_idx2].men_text clipped, " ..."
                  end if
               end if
               let men_idx2 = men_idx2 + 1
            end foreach
            let sav_indx = men_idx2 -1
            for men_idx1 = men_idx1 to 32
               hide option men_array[1,men_idx1].men_text
            end for
            if sav_indx < 9 then
               call scr1_loop(4,20,1,sav_indx)
            else
               if sav_indx > 8 and sav_indx < 16 then
                  call scr1_loop(4,20,1,sav_indx)
               else
                  call scr1_loop(4,2,1,sav_indx/2)
                  call scr1_loop(4,41,(sav_indx/2)+1,sav_indx)
               end if
            end if
      command men_array[1,1].men_text
         if run_option (men_array[1,1].*) = "M" then
            exit menu
         end if
      command men_array[1,2].men_text
         if run_option (men_array[1,2].*) = "M" then
            exit menu
         end if
      command men_array[1,3].men_text
         if run_option (men_array[1,3].*) = "M" then
            exit menu
         end if
      command men_array[1,4].men_text
         if run_option (men_array[1,4].*) = "M" then
            exit menu
         end if
      command men_array[1,5].men_text
         if run_option (men_array[1,5].*) = "M" then
            exit menu
         end if
      command men_array[1,6].men_text
         if run_option (men_array[1,6].*) = "M" then
            exit menu
         end if
      command men_array[1,7].men_text
         if run_option (men_array[1,7].*) = "M" then
            exit menu
         end if
      command men_array[1,8].men_text
         if run_option (men_array[1,8].*) = "M" then
            exit menu
         end if
      command men_array[1,9].men_text
         if run_option (men_array[1,9].*) = "M" then
            exit menu
         end if
      command men_array[1,10].men_text
         if run_option (men_array[1,10].*) = "M" then
            exit menu
         end if
      command men_array[1,11].men_text
         if run_option (men_array[1,11].*) = "M" then
            exit menu
         end if
      command men_array[1,12].men_text
         if run_option (men_array[1,12].*) = "M" then
            exit menu
         end if
      command men_array[1,13].men_text
         if run_option (men_array[1,13].*) = "M" then
            exit menu
         end if
      command men_array[1,14].men_text
         if run_option (men_array[1,14].*) = "M" then
            exit menu
         end if
      command men_array[1,15].men_text
         if run_option (men_array[1,15].*) = "M" then
            exit menu
         end if
      command men_array[1,16].men_text
         if run_option (men_array[1,16].*) = "M" then
            exit menu
         end if
      command men_array[1,17].men_text
         if run_option (men_array[1,17].*) = "M" then
            exit menu
         end if
      command men_array[1,18].men_text
         if run_option (men_array[1,18].*) = "M" then
            exit menu
         end if
      command men_array[1,19].men_text
         if run_option (men_array[1,19].*) = "M" then
            exit menu
         end if
      command men_array[1,20].men_text
         if run_option (men_array[1,20].*) = "M" then
            exit menu
         end if
      command men_array[1,21].men_text
         if run_option (men_array[1,21].*) = "M" then
            exit menu
         end if
      command men_array[1,22].men_text
         if run_option (men_array[1,22].*) = "M" then
            exit menu
         end if
      command men_array[1,23].men_text
         if run_option (men_array[1,23].*) = "M" then
            exit menu
         end if
      command men_array[1,24].men_text
         if run_option (men_array[1,24].*) = "M" then
            exit menu
         end if
      command men_array[1,25].men_text
         if run_option (men_array[1,25].*) = "M" then
            exit menu
         end if
      command men_array[1,26].men_text
         if run_option (men_array[1,26].*) = "M" then
            exit menu
         end if
      command men_array[1,27].men_text
         if run_option (men_array[1,27].*) = "M" then
            exit menu
         end if
      command men_array[1,28].men_text
         if run_option (men_array[1,28].*) = "M" then
            exit menu
         end if
      command men_array[1,29].men_text
         if run_option (men_array[1,29].*) = "M" then
            exit menu
         end if
      command men_array[1,30].men_text
         if run_option (men_array[1,30].*) = "M" then
            exit menu
         end if
      command men_array[1,31].men_text
         if run_option (men_array[1,31].*) = "M" then
            exit menu
         end if
      command men_array[1,32].men_text
         if run_option (men_array[1,32].*) = "M" then
            exit menu
         end if
      command key (Esc,"E","X")
         let end_menu = "Y"
         Exit Menu
      command "Quit"
         let end_menu = "Y"
         Exit Menu
   end menu
end while

end function

function run_option(wrk_recd)

   define
      wrk_recd record
      wrk_mncd like mndt_tabl.mndt_mncd,
      wrk_numb like mndt_tabl.mndt_numb,
      wrk_type like mndt_tabl.mndt_type,
      wrk_text char(37),
      wrk_path like mndt_tabl.mndt_path
   end record,
   wrk_rowid integer

   if wrk_recd.wrk_type = "M" then
      call show_menu(wrk_recd.wrk_path)
   else
      if wrk_recd.wrk_type = "P" then
            run wrk_recd.wrk_path clipped
      else
         if wrk_recd.wrk_type = "F" then
            call redirector(wrk_recd.wrk_path)
         end if
      end if
   end if
   return wrk_recd.wrk_type
end function

function scr1_loop(strt_line, strt_post, strt_indx, stop_indx)

   define
      strt_line smallint,
      strt_post smallint,
      strt_indx smallint,
      stop_indx smallint

   for strt_indx = strt_indx to stop_indx
      display men_array[2,strt_indx].men_text at strt_line, strt_post
      let strt_line = strt_line + 1
   end for
end function

The schemas of the tables you will need are below:

create table mnms_tabl
  (
    mnms_mncd char(6) not null,
    mnms_synm char(30) not null,
    mnms_mnnm char(40) not null
  );
create unique cluster index mnms_idx1 on mnms_tabl(mnms_mncd);

create table mndt_tabl
  (
    mndt_mncd char(6) not null,
    mndt_numb smallint not null,
    mndt_type char(1) not null,
    mndt_text char(34) not null,
    mndt_path char(34) not null
  );

create unique cluster index mndt_idx1 on mndt_tabl (mndt_mncd,mndt_numb);

Just a little explanation: MNMS is the Menu header which contains a system
name and a menu name. This is linked to MNDT in a one to many relationship
where each MNDT is a menu option. The row contains a sequence number, an
option type, the text of the option and a path to the executable or
function. Now there are 4 mndt_types: "T" is just text which is displayed
on the screen, "M" which leads to a submenu (i.e. mndt_path  must contain a
menu code), "P" which runs a free-standing program (i.e. mndt_path must
contain something like "fglgo xyz" or "vi xyz.4gl") and finally "F" which
leads to a function. Since I have not found any way to call a variable
function name, "F" is implemented via a function called redirector which is
a massive case statement of the form "CASE function when "a()" call a()
                    when "b()" call b()
                             ....
                     otherwise display "don't know that one!"

The program takes care of centering the options on the screen  and looks
pretty good. If you get this working and make it sexier, please send me a
copy.

Andrew Cilia - Philip Toledo Limited

At 14:11 29/09/97 -0400, you wrote:
>MIS Dept wrote:
>>
>> We're modifying our menu structure for our homegrown Informix code.
Instead of creating
>> a ring menu with all various front-end programs linked into a single
executable, we're
>> looking to split out the various front-ends into separate executables,
then create a
>> table-driven menu structure.  While we can make a 'drop down' style menu
relatively
>> easy, we would like to keep the ring menu structure for our user
community.  Any way to
>> create a table-driven ring menu?  I figure that someone may have already
asked this
>> question, but I could find no reference in the newsgroup archive.
>
>Here's a kludge to accomplish this:
>
>1) Initialize arrays of strings for menu choices and prompts to NULL.
>2) In the code, physically before executing the menu statement, fetch
>  the actual choices and prompts into the array.
>3) Create a menu with the maximum number of items possible using
>  an array of variables for the choice and prompt strings for all.  In
>  the code for BEFORE MENU clause test if the choice for each array
>  element corresponding to the menu item is NULL, if NULL execute HIDE
>  OPTION choice[n] otherwise execute SHOW OPTION choice[n].
>4) The command for each choice (except any fixed choices like EXIT)
>  would be a call to a function, passing the choice number or name,
>  which would execute the appropriate code based on the argument(s)
>  passed to it.  This function could be written in 4GL with a big case
>  statement or "C" using an array of function names or id#s and
>  function pointers.
>
>You get the picture.  The only rub is the phrase "maximum possible
>number of choices" this may be hard to determine at coding time.
>
>Art S. Kagel
>