Add additional submenus
Ben Murphy-Baum
There are many times when I've wanted to programmatically create new submenus within a PopUpContextualMenu, and to allocate items to different submenus. This doesn't seem to be possible right now -- although you can dynamically adjust Menu items, the submenus themselves must be hard-coded into the Menu definition from the start. Instead, I'd like the end user to be able to add submenus to an existing menu definition on the fly using something like AddSubMenu(submenuName,addToMenuName,itemListString).
They can already do this by writing their own menu definition using the same menu name.
Here's an example:
"Hello", Beep
Submenu "Color"
"*COLORPOP*", DoSomethingWithColor()
End
Submenu "A Waves"
WaveList("A*",";",""), /Q, DoSomethingWithWave()
End
End
Function DoSomethingWithColor()
GetLastUserMenuInfo
Print V_Red, V_Green, V_Blue, V_Alpha
End
Function DoSomethingWithWave()
GetLastUserMenuInfo
WAVE w = $S_value
Print "User selected "+GetWavesDataFolder(w,2)
End
Macro tryIt()
Make/O Awave0, Awave1
Make/O Bwave0, bwave1
PopupContextualMenu/N "ForContext"
if( V_flag < 0 )
Print "User did not select anything"
endif
End
// End User writes their own addition to the ForContext menu
Menu "ForContext", contextualmenu, dynamic
"This is Mine", /Q, Print "This is Mine"
Submenu "B Waves"
WaveList("B*",";",""), /Q, DoSomethingWithWave()
End
End
January 26, 2021 at 04:03 pm - Permalink
Hi Jim,
That's definitely useful, but for this case I'm looking more for something where I can have a pre-written program dynamically resolve how many submenus to create, what they should be called, and what items to put into each one.
For my purpose, I'm allowing the user to write their own functions that can be tagged with a submenu assignment in a commented line below the function definition (shown below). I can extract this code as a string using ProcedureText, and I want to resolve the submenu they wish to assign that function to, and then build it into a contextual pop up menu. The idea is to have a menu drop down with all of the user's functions organized as they please into various submenus. Every time a user writes a new function, that's all they have to do--the GUI will automatically find it and parse the functions into their appropriate submenus. Thanks for your help.
Variable input1,input2,input3
//SUBMENU=Submenu1
//code....
End
January 26, 2021 at 04:29 pm - Permalink
In reply to Hi Jim, That's definitely… by Ben Murphy-Baum
In Jim's example, the menu with the 'dynamic' keyword is built on-the-fly. Instead of Wavelist you can supply an arbitrarily complex string function, with the caveat that adding many menus or using slow text processing will make things sluggish.
But, for what you describe, I don't think the menu needs to be dynamic. Building the menu at compile time will catch any new functions.
For global user functions that take no parameters, this works:
UserFuncList()
end
function /s UserFuncList()
string s = functionlist("*", ";", "KIND:2,NPARAMS:0")
s = removeFromList(functionlist("*", ";", "KIND:1,NPARAMS:0"), s)
return s
end
function test()
print "hi"
end
You could supply a wrapper function that executes the selected user function if you need to collect parameters or something.
Use GetLastUserMenuInfo to retrieve the menu selection:
UserFuncList(), MyWrapperFunc()
end
function /s UserFuncList()
string s = functionlist("*", ";", "KIND:2,NPARAMS:0")
s = removeFromList(functionlist("*", ";", "KIND:1,NPARAMS:0"), s)
return s
end
function MyWrapperFunc()
GetlastUserMenuInfo
doalert 0, "you selected "+s_value
end
January 27, 2021 at 12:30 am - Permalink
... but I don't think there's an option for programmatically adding or removing submenus, unfortunately.
January 27, 2021 at 05:28 am - Permalink
Give this a try:
"Hello", Beep
Submenu SubmenuStr(0)
SubmenuItems(0)
End
Submenu SubmenuStr(1)
SubmenuItems(1)
End
Submenu SubmenuStr(2)
SubmenuItems(2)
End
Submenu SubmenuStr(3)
SubmenuItems(3)
End
Submenu SubmenuStr(4)
SubmenuItems(4)
End
Submenu SubmenuStr(5)
SubmenuItems(5)
End
Submenu SubmenuStr(6)
SubmenuItems(6)
End
Submenu SubmenuStr(7)
SubmenuItems(7)
End
Submenu SubmenuStr(8)
SubmenuItems(8)
End
Submenu SubmenuStr(9)
SubmenuItems(9)
End
End
Macro tryIt()
PopupContextualMenu/N "ForContext"
print V_flag, S_selection
End
Function/S SubmenuStr(Variable num)
if (num < 4)
return "Submenu" + num2istr(num)
else
return "-"
endif
End
Function/S SubmenuItems(Variable submenuNum)
Variable itemNum = 0
String itemsList = ""
For (itemNum = 0; itemNum < 5; itemNum++)
itemsList = AddListItem("Submenu" + num2istr(submenuNum) + ", Item" + num2istr(itemNum), itemsList, ";", inf)
EndFor
return itemsList
End
If you can live with writing your "ForContext" menu definition to contain a maximum number of submenus (in the example, I made up to 10 possible) then I think you can do what you want.
In your situation you would modify SubmenuStr to handle all of the parsed submenus found in the code.
Note that this works because our menu code will remove any menu items that are dividers if they are not followed by a non-divider menu item. Returning "-" from SubmenuStr makes that submenu a divider.
January 27, 2021 at 06:19 am - Permalink
In reply to Give this a try: Menu … by aclight
Ahh thanks Adam. I had actually tried something like this, but was trying to return an empty string to the submenu definition, which it wasn't allowing. That should solve it!
January 27, 2021 at 09:49 am - Permalink