MathGroup Archive 2009

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Multi-level Menu (ActionMenu)

Hi Chris,

Below is the closest analog I found (I am not a UI person and you will
probably get better solutions from others, but still) : suppose your menu
data is in such a structure:

In[1] =

menuItems =
    {{"Algeria", {"Algiers",  "Oran"}},
     {"Angola", {"Luanda", "Huambo"}}}
{"North America",
    {{"United States", {"New York", "Washington"}},
     {"Canada", {"Toronto", "Montreal"}}}

The first auxiliary function adds actions to the lower-level menu items:

In[2] =
addLowestItemActions[menuItemTree_, f_] :=
  Map[# :> f[#] &, menuItemTree, {Depth[menuItemTree] - 1}];


In[3] =
addLowestItemActions[menuItems, h]

Out[3] =

 {{"Africa", {{"Algeria", {"Algiers" :> h["Algiers"],
     "Oran" :> h["Oran"]}}, {"Angola", {"Luanda" :> h["Luanda"],
     "Huambo" :>    h["Huambo"]}}}}, {"North America", {{"United States",
{"New York" :> h["New York"],
     "Washington" :> h["Washington"]}}, {"Canada", {"Toronto" :>
      h["Toronto"], "Montreal" :> h["Montreal"]}}}}}

Another auxilliary function will transform the structure as needed in

In[4] =

menuItemsConvert[itemsAndActions_, menuDepth_Integer,
    submenuConstructionFnames_List] /;
   Length[submenuConstructionFnames] == menuDepth - 1 :=
  Fold[Function[{expr, fandlevel},
    With[{fn = fandlevel[[1]]},
     Apply[# :> fn[##] &, expr, fandlevel[[2]]]]], itemsAndActions,
     List /@ Range[2*menuDepth - 3, 1, -2]}]];


In[5] =
menuItemsConvert[addLowesItemActions[menuItems, h], 3, {f, g}]

Out[5] =

 {"Africa" :>
  g["Africa", {"Algeria" :>
     f["Algeria", {"Algiers" :> h["Algiers"], "Oran" :> h["Oran"]}],
    "Angola" :>
     f["Angola", {"Luanda" :> h["Luanda"],
       "Huambo" :> h["Huambo"]}]}],
 "North America" :>
  g["North America", {"United States" :>
     f["United States", {"New York" :> h["New York"],
       "Washington" :> h["Washington"]}],
    "Canada" :>
     f["Canada", {"Toronto" :> h["Toronto"],
       "Montreal" :> h["Montreal"]}]}]}

Finally, the main menu-building function:

createDepth3CountryDataMenu[menuItemTree_, actionF_] :=
 With[{menudepth = 3},
  Module[{name , subname, sub, subsub, subBack, makeSub, subsubBack,
    makeSubSub, subsubname = "Cities"},
   subBack[] := (sub = ""; name = "Continent");
   subsubBack[] := (subsub = ""; subname = "Country");
   makeSub[nm_String, actions_List] :=
    (name = nm;
     sub := ActionMenu[subname,
       Prepend[actions, "Back" :> (subsubBack[]; subBack[])]]);
   makeSubSub[nm_String, actions_List] :=
    (subname = nm;
     subsub := ActionMenu[subsubname,
       Prepend[actions, "Back" :> subsubBack[]]]);
   With[{menuContent = menuItemsConvert[
       addLowestItemActions[menuItemTree, actionF],
       menudepth, {makeSubSub, makeSub}]},
    Dynamic[Row[{ActionMenu[name, menuContent], sub, subsub}]]]]]

It is less generic than the previous two. It is possible to write it in a
more generic way to allow it to automatically adjust to the input menu
structure, but the code will look more complex. It will however then become
more elegant and robust. In particular, it is possible to generate functions
like makeSub, makeSubSub automatically, as well as variables <sub>,
<subsub>. Note that all functions rely on a particular list data structure
used to store the menu items.

The usage (for example):

createDepth3CountryDataMenu[menuItems ,
 Print["The city you chose is ", #] &]

Hope this helps.


On Mon, Jun 8, 2009 at 3:18 AM, Chris Degnen <degnen at> wrote:

> Hi,  Any suggestions for creating a multi-level menu, such as this:

  • Prev by Date: Re: Coding for Mathematica
  • Next by Date: Re: Re: performance // Re: Re: Why
  • Previous by thread: Multi-level Menu (ActionMenu)
  • Next by thread: Re: Multi-level Menu (ActionMenu)