• 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[{
"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},
Dynamic[
If[Length[stack] >= i, stack[[i]], defaultlabel]
],
Map[
toLabel[#] :> (
stack = Append[Take[stack, i - 1], toLabel[#]];
createNextLevel[{levels, stack}, #, action, opts];
) &,
items
],
]
]
];

(* main function to call *)

"AppearanceWrapper" -> Row, "DefaultLabels" -> {},
}];

nestedActionMenu[items_List, action_: None, opts : OptionsPattern[]] :=
With[{
defaultlabel =
Function[If[Length[#] > 0, #[[1]], "Choose"]][
OptionValue["DefaultLabels"]]
},
DynamicModule[{
levels, stack = {}
},
Dynamic[If[Length[stack] > 0, stack[[1]], defaultlabel]],
Map[
toLabel[#] :> (
stack = {toLabel[#]};
createNextLevel[{levels, stack}, #, action, opts]) &,
items
],
];
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! *)
"Africa" -> {
"Algeria" -> {"Algiers", "Oran"},
"Angola" -> {"Luanda", "Huambo"}
},
"North America" -> {
"United States" -> {"New York", "Washington"},
}
}
]

(* example with actions, they can be given globaly or locally for \
each entry *)
"Africa" -> {
"Algeria" -> {"Algiers", "Oran"},
"Angola" -> {"Luanda", "Huambo"}
},
"North America" -> {
"United States" -> {"New York", "Washington"},
"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
*)
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"}]

(*
we use the option "AppearanceWrapper" for further formatting...
*)
SetOptions[EvaluationNotebook[],
DockedCells -> {
Cell[BoxData[ToBoxes[Button["City Information",
CreateDialog[{ExpressionCell[Panel[

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....