Windowmenubar and custom context menus

windowmenubar (and filemenubar and globalmenubar) are behaving strangely when creating a custom context menu. This works as expected to generate a custom menu when right-clicking on the data sheet:

windowmenubar "",menu("Context")+
    menuitem("One","CODE","message '1'")+
    menuitem("Two","CODE","message '2'")+
    menuitem("Three","CODE","message '3'"),
"DATA_CONTEXTMENU"

but if I put the result of that menu-generating expression into a variable and use that as the second parameter of windowmenubar it no longer works — no context menu appears when right-clicked:

let ThisMenu=menu("Context")+
    menuitem("One","CODE","message '1'")+
    menuitem("Two","CODE","message '2'")+
    menuitem("Three","CODE","message '3'")
windowmenubar "",ThisMenu,"DATA_CONTEXTMENU"

If I replace the expression with the equivalent LMSL text, in each case the result is unchanged.

However, to create a new menu-bar menu, both of those approaches work:

windowmenubar "basic",menu("New menu")+
    menuitem("One","CODE","message '1'")+
    menuitem("Two","CODE","message '2'")+
    menuitem("Three","CODE","message '3'"),
"DATA_MENUBAR"

and

let ThisMenu=menu("New menu")+
    menuitem("One","CODE","message '1'")+
    menuitem("Two","CODE","message '2'")+
    menuitem("Three","CODE","message '3'")
windowmenubar "basic",ThisMenu,"DATA_MENUBAR"

And both also work with ,"DATA_MENUBAR" omitted, as they should.

So why does generating as menu-bar menu work, but not a context menu, when the menu is held in a variable?

Incidentally, the help text for menuitem( states: ‘If the menu is installed in the main menu bar (at the top of the screen), the default action is to call the .CustomMenu procedure in the current database. . . . If the menu is a context menu (right click) the default is to invoke the ContextMenuAction statement . . .’ As far as I can see there is no contextmenuaction statement, and I’m not sure what it would mean in this context to invoke it. I thought it might mean that the default is to call a .ContextMenuAction procedure instead, but that doesn’t seem to happen either. That is why my menus above include explicit code for each menu option, otherwise I can’t see how a custom context menu can do anything useful. Or am I missing something obvious?

You are using a local variable - this should never work. You say that it does work if used for a DATA_MENUBAR, but I don’t see how it could. The local variable only exists for the duration of the procedure, then it vanishes. When Panorama goes to draw the menu, there is no variable, so it doesn’t work.

The correct way to do this is to use a windowglobal variable, like this:

letwindowglobal Thismenu=...
windowmenubar "basic",ThisMenu,...

The windowglobal variable will remain active as long as the window remains open.

Looks like I half implemented this and half documented it. In the meantime, you came up with the correct solution, using the CODE option.

I think that is what I meant to do. It looks like there are pieces of this in the code, but they are not complete.

Ah, yes, thank you. I was missing something obvious: variable scope.

On the subject of unfinished business, I arrived at a custom context menu in the data sheet because I need a popup menu with a heirarchy of submenus and, as you predicted would eventually happen, the temporary hack I mentioned in this thread five years ago no longer works:

I briefly thought there might be another solution, because I found the popupdoublefieldchoices command which does exactly what I was looking for — except, predictably, the submenus it generates don’t work.

I found the popupdoublefieldchoices procedure in _FormLib — which is useful anyway, because the code for generating the menus and submenus is much more compact, elegant and probably faster than my own. But essentially it’s doing the same as I was doing in the above thread: generating a series of menus and then using popupbutton to display them, which won’t work until the various popup menu commands can handle submenus.

This problem does come up in the forum from time to time. I know it’s difficult because the Apple code isn’t properly documented, but the OS makes extensive use of heirarchical popup menus, especially in the Finder, so is there any chance that this might be fixed one day?

Upon further research, I’ve discovered that the code for context menus was actually copleted, but it was documented incorrectly.

If a context menu item doesn’t have any code associated with it, Panorama will look for the .CustomMenu procedure and call it if it is available. The .CustomMenu procedure can use info(“trigger”) to find out what was chosen. However, there is no menu name, only an item name. So the trigger will be something like

Menu..Three

This works now, in the currently shipping copy of Panorama (and probably has worked this way for several years). I’ve updated the documentation with this information.


I’ve also given more thought to storing the menu items in a variable. I told you to use a windowglobal variable, but I think that this is bad practice. You should put the formula directly into the windowmenubar statement, as shown in the documentation.

The reason I say this is, what if your menu code contains some logic? For example, suppose the second menu item should only appear if there are more than two items. You might think you could do this.

letwindowglobal ThisMenu=menu(“Context”)+
menuitem(“One”,“CODE”,“message ‘1’”)+
?(items>2,menuitem(“Two”,“CODE”,“message ‘2’”),“”)+
menuitem(“Three”,“CODE”,“message ‘3’”)
windowmenubar “”,ThisMenu,“DATA_CONTEXTMENU”

The problem is, the comparison for items>2 will be run when you assign the value to the variable. But you don’t want this comparison to happen until the user actually clicks to pop up the menu. That’s when you want to decide whether or not to show the menu. In a simpler case you might want the menu item name to be based on a variable. Or you might use arraymenuitem( to build the menu based on an array. In all of those cases, you want the actual calculation to happen at the time the user clicks on the menu, not the time when the variable is assigned.

In your example, there is no logic, no variables, so it doesn’t really matter, it works the same either way because the menu items are fixed. But I think this is a bad habit to get into. And what is the advantage of putting this in a variable? As far as I can see, none.


This is not really comparable. The Finder uses a fixed menu arrangement, it’s set up statically. Panorama generates the menus dynamically, as they are used. You may say “but I just need fixed, static menus” but you can’t really go into Xcode and set up the fixed assets, can you?

The point is, it doesn’t really matter what the Finder does. I could certainly build a heirarchical popup menu in ObjC, but it would be a fixed menu of my design, not the menu arrangement you want. The trick is getting Panorama’s dynamic menu system working with heirarchical menus. The Finder doesn’t do that. The Finder is not a user interface toolkit.

I’ve spent quite a bit of time on this problem on two separate occasions. I would really like this capabillity myself, it would be very useful. But it is a rather intractable problem. I went back and read the old thread you mention and all of the frustration and dead ends came back to me. I’m sure I’ll give this a crack again someday, but I don’t think this is a problem where I can sit down and say “I’m not getting up until this is fixed”.

Buddha did that and it took him 49 days.