Positioning popup menus

I'm not a big fan of right click menus. In many applications they are implemented incorrectly and cannot be triggered with the context menu key or the standard Shift+F10 combination. They also seem to be sort of a dump bin for many developers. Instead of thinking how to incorporate a new feature in a useful way, it's just added to all right click menus on the form. Lastly, right click menus are hardly discoverable for the end user. Having to click on every pixel just to discover whether there's some hidden feature is great for games, but not really appropriate for any productive application.
Back to the topic. There are times when it makes sense to provide less frequently used features on a form. For instance, a useful feature for a name textbox is to open a browser window with a web search. For such features I use a small button close to the textbox that displays a down arrow ("u" using the Marlett font). This button opens a small popup menu just below the button much in the same way you see this all over in Microsoft Office.

Positioning popup menus can be a little difficult in Visual FoxPro. The Menu Designer produces code that uses MCOL() and MROW() to position the menu at the mouse cursor. This works fine unless you click somewhere on the window title. In this case, the two functions return -1 moving the popup somewhere outside the window.

When you try to move the popup elsewhere you quickly realize that you have to give the position in Foxels instead of pixels. Foxels are in Visual FoxPro what Twips are in Visual Basic. A Foxel depends on the size of the current font of a form. In other words, changing Thisform.FontName or any other font related property changes the measurement for Foxels.

The rarely used ScaleMode property allows you to specify form coordinates in Foxels or pixels. As a side note: Switching a form to Foxels is a good way to break generic third party components. Most developers don't deal very well with positions that have decimal places and add pixels to Left, Top, Width, and Height without checking the scale mode before.

Hence, to position a popup control just below or above a command button, you switch the form scale mode, read the button position in Foxels and switch back to pixels. This works fine for buttons that are placed on the form directly. With nested controls, though, you have to use OBJTOCLIENT(), a function that completely ignores the ScaleMode property. To get around this, I add an invisible button right to the form:


Local lnRow, lnColumn
If Vartype(Thisform.PosHelp) != "O"
Thisform.AddObject("PosHelp","Commandbutton")
EndIf
Thisform.PosHelp.Move( ;
Objtoclient(This,2), ;
Objtoclient(This,1)+This.Height ;
)
Thisform.ScaleMode = 0
lnRow = Thisform.PosHelp.Top
lnColumn = Thisform.PosHelp.Left
Thisform.ScaleMode = 3

With the position in Foxels I can now define a popup menu like this:


DEFINE POPUP shortcut ;
SHORTCUT RELATIVE ;
From m.lnRow, m.lnColumn ;
Font Thisform.FontName, This.FontSize
Define bar 1 of Shortcut Prompt "Item 1"
Define bar 2 of Shortcut Prompt "Item 2"
Define bar 3 of Shortcut Prompt "Item 3"
Activate Popup Shortcut

Just in case you wonder about the FONT clause used here. Some clients insist on a resizer control on the form. That is, when they resize the form, the content becomes larger. With this clause the popup menu has the same size as everything else on the form.