File MIES_GuiPopupMenuExt.ipf

Helper functions related to GUI controls.

These procedures provide a way to replace popup menus with many entries with context menus. Context menus can provide submenus, that allow better organization of menu entries.


Function SetupPopupMenuExt()
    KillWindow/Z panel0
    Button popupext_menu1, pos={3.00, 20.00}, size={200,20},proc=PEXT_ButtonProc,title="DropDownMenu1 ▼", userdata($PEXT_UDATA_POPUPPROC)="DemoProc", userdata($PEXT_UDATA_ITEMGETTER)="GetMenuList1"
    Button popupext_menu2, pos={3.00, 55.00}, size={200,20},proc=PEXT_ButtonProc,title="DropDownMenu2 ▼", userdata($PEXT_UDATA_POPUPPROC)="DemoProc", userdata($PEXT_UDATA_ITEMGETTER)="GetMenuList2"
    Button popupext_menu3, pos={3.00, 90.00}, size={200,20},proc=PEXT_ButtonProc,title="DropDownMenu3 ▼", userdata($PEXT_UDATA_POPUPPROC)="DemoProc", userdata($PEXT_UDATA_ITEMGETTER)="GetMenuList3"

Function DemoProc(pa) : PopupMenuControl
    STRUCT WMPopupAction &pa

    print "EventCode/Win/Selected/ctrlName: ", pa.eventCode,, pa.popStr, pa.ctrlName

Function/S GetMenuList1()

    Make/FREE/T/N=300 testItems = num2char(97 + mod(p, 26)) + "_" + num2str(p)
    return TextWaveToList(testItems, ";")

Function/WAVE GetMenuList2(device)
    string device

    Make/FREE/T/N=(2) menus
    menus[0] = "Kriemhild;Brünhild"
    menus[1] = "Siegfried;Gunther"
    SetDimLabel ROWS, 0, $"Women", menus
    SetDimLabel ROWS, 1, $"Men", menus

    return menus

Function/WAVE GetMenuList3(device)
    string device

    Make/FREE/T menus = {"Kriemhild", "Brünhild", "Siegfried", "Gunther"}
    WAVE/T splitMenu = PEXT_SplitToSubMenus(menus, method = PEXT_SUBSPLIT_ALPHA)
    return splitMenu

The original popupmenu has to be replaced by a button with the PEXT_ButtonProc as procedure. The userdata of the button stores as list with key value pairs a function that returns the menu item list and a function that is the PopupMenuControl procecure of the former popupmenu. The function for the menu item list corresponds to the function given for a popupmenu as e.g. value=GetMenuList1() that returns a string with semicolon separated list of menu items. The names for the submenus are generated automatically in that case. If one wants to disable the menu, return “” as menu item list. Then a disabled “_none_” is shown that can not be selected.

The constants PEXT_UDATA_ITEMGETTER and PEXT_UDATA_POPUPPROC were defined for the keys in the userdata string.

When a user selects an entry in the context menu the PopupMenuControl control defined through PEXT_UDATA_POPUPPROC is called. So the proc of the previous popupmenu can be used without further adaptations.

User defined sub menus:

User defined submenus can be created as well. Therefore an extension was added to the function that returns the menu items. Instead of a string as described before a function can be defined that returns a 1D text wave, e.g. GetMenuList2() in the example. Each element contains a semicolon separated list of menu items. Each rows DimLabel is used as submenu name, where the elements menu items are put. The DimLabels must not be empty. The wave can have up to MAX_SUBMENUS elements. The button popupext_menu2 shows this extension in the example.

Half automatic generation:

Example 3 from Button popupext_menu3 shows how a menu is created by defining a wave with menu items first. Then the menu items are split to sub menus with PEXT_SplitToSubMenus using the method PEXT_SUBSPLIT_ALPHA. In the second step the sub menu named are generated with the default algorithm by calling PEXT_GenerateSubMenuNames.

Method Description


In each sub menu up to NUM_SUBENTRIES menu items are placed. If MAX_SUBMENUS number of sub menus are reached then the remaining menu items are placed in the last sub menu.


In each sub menu up to NUM_SUBENTRIES menu items are placed. If the beginning letter of the last menu item in the sub menu differs from the beginning letter of the first menu item then the menu items in the sub menu get reduced. All menu item beginning with the letter of the last menu item are moved to the next sub menu. If the beginning letters match then no menu items get moved. If MAX_SUBMENUS number of sub menus are reached then the remaining menu items are placed in the last sub menu.


In a sub menu from the first and last menu item the number of letters from the beginning is counted until the letters do not match. This part of the menu item is used and taken as a sub menu name in a range notation: Alfons, Aluminium -> Alf .. Alu This is also applied between different sub menus, so the last menu item and the first menu item of the next sub menu. If in the previous sub menu the number of letters determined for the last menu item is higher then for the first name component the higher amount is taken: e.g. Balalaika, Cembalo -> B .. C -> Bal .. C (because Alu were three letters)


string PEXT_SubMenuName(variable subMenuNr)

Menu definition templates for up to MAX_SUBMENUS sub menus. The constant MAX_SUBMENUS stores the number of these definitions and must be updated if more definitions are added.

Returns sub menu names for all PEXT sub menus This is called on each menu click/compilation for all dynamic defined Menus where PEXT_SubMenuName is used.


subMenuNr – number of current sub menu

string PEXT_PopupMenuItems(variable subMenuNr)

Returns menu items for all PEXT menus This is called on each menu click/compilation for all dynamic defined Menus where PEXT_PopupMenuItems is used.

Callled very often (MAX_SUBMENUS^2/2).


subMenuNr – number of current sub menu

variable PEXT_Callback(string popupStr, string text, variable itemNum)

This callback is executed when the user selected a PEXT dynamic menu item. It is not called if the user aborted the menu by clicking somewhere else.

  • popupStr – popup string

  • text – selected menu item text

  • itemNum – selected item index in submenu


Prototype for the menu item getter that allows user defined sub menu attribution of menu items.

wave PEXT_ITEMGETTER_WAVE_PROTO(string device)

Prototype for the menu item getter that is compatible with the former popupmenu value=procedure definition.

variable PEXT_POPUPACTION_PROTO(WMPopupAction *pa)

Prototype for the former popupaction procedure, that is only called virtually now through the PopupContextualMenu callback.


pa – WMPopupAction structure

variable PEXT_ButtonProc(WMButtonAction *ba)

Generic procedure for button actions from popup extension controls Fills the global popupExtMenuInfo wave with current menu setup information retrieved from the function defined in the buttons userdata through PEXT_UDATA_ITEMGETTER key. This getter function can either return a string or 1D text wave.


ba – WMButtonAction structure

static variable PEXT_VerifyAndSetMenuWave(WaveTextOrNull menuWave)

Verifies menu data input wave and transfers it to global.

static variable PEXT_SetDisabledMenu()

Sets the menu to show a non selectable “_none_” entry.

wave PEXT_SplitToSubMenus(WaveTextOrNull menuList, variable method = defaultValue)

Automatically splits a 1D text wave with menu items to submenus This function does not name submenus.

See also


  • menuList[in] 1d text wave with menu items

  • method[in] [optional, default = PEXT_SUBSPLIT_DEFAULT] sets how the menu items are split to sub menus


1d text wave where each element contains a list of menu items. Each element represents a sub menu.

variable PEXT_GenerateSubMenuNames(WaveTextOrNull splitMenu, variable method = defaultValue)

Automatically generates submenu names and applies them on the given wave.

See also


  • splitMenu[in] 1d text wave with menu item lists for sub menus as returned by PEXT_SplitToSubMenus()

  • method[in] [optional, default = PEXT_SUBNAMEGEN_DEFAULT] sets how the sub menu names are generated


static const double MAX_SUBMENUS = 12
static const string WAVE_NOTE_PROCNAME = "PROC"
static const string WAVE_NOTE_WINDOWNAME = "WINNAME"
static const string WAVE_NOTE_CTRLNAME = "CTRLNAME"
static const string MENUNAME_UNUSED = "*** bug, report to dev ***"
static const string MENU_DISABLE_SPECIAL = "\\M0"
static const string LSEP = ";"