MathGroup Archive 2009

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

Search the Archive

Re: Generic nested menus implementation

  • To: mathgroup at smc.vnet.net
  • Subject: [mg100658] Re: Generic nested menus implementation
  • From: Albert Retey <awnl at gmx-topmail.de>
  • Date: Wed, 10 Jun 2009 17:10:15 -0400 (EDT)
  • References: <h0nums$bfl$1@smc.vnet.net>

Hi,

I have played around with your initial idea also, and appended is what I
came up with...

hth,

albert

(* START OF CODE *)
(* just a little helper *)
ClearAll@toLabel;
toLabel[s_String] := s;
toLabel[s_String -> l_List] := s;
toLabel[s_String :> _] := s;

(* the heart of the code: recursive definition of the action menues *)


ClearAll@createNextLevel;

SetAttributes[createNextLevel, HoldFirst];

Options[createNextLevel] = Flatten[{
    Options[ActionMenu], "AppearanceWrapper" -> Row,
    "DefaultLabels" -> {}
    }];

createNextLevel[{levels_, stack_}, label_String, action_,
   opts : OptionsPattern[]] := (
   Do[levels[i] =., {i, Length[stack] + 1,
     Max[DownValues[levels][[All, 1, 1, 1]]]}];
   action[stack]
   );

createNextLevel[{levels_, stack_}, label_String :> myaction_, action_,
    opts : OptionsPattern[]] := (
   Do[levels[i] =., {i, Length[stack] + 1,
     Max[DownValues[levels][[All, 1, 1, 1]]]}];
   myaction
   );

createNextLevel[{levels_, stack_}, label_String -> items_List,
   action_, opts : OptionsPattern[]] := With[{
    defaultlabel = Function[
       Which[
        Length[#] >= Length[stack] + 1, #[[Length[stack] + 1]],
        Length[#] > 0, Last[#],
        True, "Choose"
        ]
       ][OptionValue["DefaultLabels"]]
    },
   Do[levels[i] =., {i, Length[stack] + 1,
     Max[DownValues[levels][[All, 1, 1, 1]]]}];
   levels[Length[stack]] = With[{i = Length[stack] + 1},
     ActionMenu[
      Dynamic[
       If[Length[stack] >= i, stack[[i]], defaultlabel]
       ],
      Map[
       toLabel[#] :> (
          stack = Append[Take[stack, i - 1], toLabel[#]];
          createNextLevel[{levels, stack}, #, action, opts];
          ) &,
       items
       ],
      FilterRules[Flatten@{opts}, Options[ActionMenu]]
      ]
     ]
   ];


(* main function to call *)

ClearAll@nestedActionMenu

Options[nestedActionMenu] = Flatten[{
    "AppearanceWrapper" -> Row, "DefaultLabels" -> {},
    Options[ActionMenu]
    }];

nestedActionMenu[items_List, action_: None, opts : OptionsPattern[]] :=
   With[{
    defaultlabel =
     Function[If[Length[#] > 0, #[[1]], "Choose"]][
      OptionValue["DefaultLabels"]]
    },
   DynamicModule[{
     levels, stack = {}
     },
    levels[0] = ActionMenu[
      Dynamic[If[Length[stack] > 0, stack[[1]], defaultlabel]],
      Map[
       toLabel[#] :> (
          stack = {toLabel[#]};
          createNextLevel[{levels, stack}, #, action, opts]) &,
       items
       ],
      FilterRules[Flatten@{opts}, Options[ActionMenu]]
      ];
    Column[{
      Dynamic[OptionValue["AppearanceWrapper"][
        Table[
         levels[i], {i, 0, Max[DownValues[levels][[All, 1, 1, 1]]]}]
        ]]
      }]
    ]
   ];
(* END OF CODE *)


(* simple example usage, with the default there are no actions! *)
nestedActionMenu[{
  "Africa" -> {
    "Algeria" -> {"Algiers", "Oran"},
    "Angola" -> {"Luanda", "Huambo"}
    },
  "North America" -> {
    "United States" -> {"New York", "Washington"},
    "Canada" -> {"Toronto", "Montreal"}
    }
  }
 ]

(* example with actions, they can be given globaly or locally for \
each entry *)
Deploy@nestedActionMenu[{
   "Africa" -> {
     "Algeria" -> {"Algiers", "Oran"},
     "Angola" -> {"Luanda", "Huambo"}
     },
   "North America" -> {
     "United States" -> {"New York", "Washington"},
     "Canada" -> {"Toronto",
       "Montreal" :> Print["Monteral is special!"]}
     }
   },
  Print,
  "DefaultLabels" -> {"Continent", "Country", "City"}
  ]

(*
somewhat more involved example,menu definition is created \
programmatically from CountryData and CityData, watch out,this will \
not work well when ContryData and CityData are not yet initialized \
and will take a while to finish
*)
menuDefinition = Map[
   Function[cont, cont -> Map[
      # -> CountryData[#, "LargestCities"][[All, 1]] &,
      CountryData[cont]
      ]
    ],
   DeleteCases[CountryData["Continents"], "Antarctica"]
   ];
(* example for a more interesting global action *)
cityinfo[{continent___, country_, city_}] := CreateDialog[{
   Grid[{
     {Style[city, "Section"],
      Show[CountryData[country, "Flag"], ImageSize -> 50]},
     {continent, country},
     {"Population", CityData[city, "Population"]},
     {"Elevation", CityData[city, "Elevation"]}
     }, Alignment -> {{Left, Right}, Automatic}], DefaultButton[]
   }]
(* check that the global action works: *)
cityinfo[{"Europe", "Switzerland", "Zurich"}]

(*
now we are ready to install the nested action menu in a "menu bar", \
we use the option "AppearanceWrapper" for further formatting...
*)
SetOptions[EvaluationNotebook[],
 DockedCells -> {
   Cell[BoxData[ToBoxes[Button["City Information",
       CreateDialog[{ExpressionCell[Panel[

           nestedActionMenu[
            menuDefinition, (DialogReturn[]; cityinfo[#]) &,
            Appearance -> None,

            "AppearanceWrapper" ->
             Function[
              Grid[{#}, Alignment -> Left, Dividers -> All,
               FrameStyle -> LightGray, ItemSize -> {10, 1}]],
            "DefaultLabels" -> {"Continent", "Country", "City"}
            ],
           ImageMargins -> 0, FrameMargins -> 0
           ],
          CellMargins -> {{0, 0}, {0, 0}}
          ]},
        WindowMargins -> {
          {MousePosition["ScreenAbsolute"][[1]],
           Automatic}, {Automatic,
           MousePosition["ScreenAbsolute"][[2]] - 40}},
        WindowFrame -> "Frameless",
        CellMargins -> 0,
        CellFrameMargins -> 0,
        WindowSize -> FitAll
        ],
       Appearance -> None
       ]
      ]],
    "DockedCell"
    ]
   }
 ]


  • Prev by Date: Re: What should be a simple task....
  • Next by Date: Re: What should be a simple task....
  • Previous by thread: Re: Generic nested menus implementation
  • Next by thread: Re: Generic nested menus implementation