I'm actually slightly bothered by the fact that the ContextualMenu control is not deprecated. The simple fact of the matter is that it's the incorrect control for almost any job you might want it to do, and the reasoning is simple: you have to work really hard to get the correct behavior out of it.
Sure, we can add all sorts of new features to it that are already elsewhere, such as the ability to make a hierarchy of menus, or add icons to items, display shortcuts, etc. However, the fact still remains that the programmer is the one responsible for showing the contextual menu, which means they are going to get it wrong most of the time.
Don't believe me? Well, let's take a look at when you should be displaying a contextual menu.
On the Mac, the menu should be displayed when the user right clicks (on mouse down), or Ctrl+Left click (on mouse down). Sometimes it should also be displayed on left click and hold (but this seems to be an optional behavior as not every application standardizes on it). However, on Windows, the menu should be displayed on right click (when the mouse is released), Shift+F10, or when the user presses the contextual menu key on their keyboard (if they have a keyboard which supports that). Then, on Linux, it's on right click (mouse up) or the contextual menu key on the keyboard. Do you think you can write some good, cross-platform code which handles all of these various behaviors very easily?
This is why we went to an event-driven approach for contextual menus. You don't have to worry about all of the mundane details about when it's appropriate to show a menu -- you are just told "make me a menu to show, if you want one shown." Then it's just a matter of constructing the menu you want displayed, and handling the return.
To do this, you make the menu in ConstructContextualMenu. You're passed in a base MenuItem class that you attach other MenuItems onto in any way you want. If you don't want to pass the event further up the call chain, you return true. It's as easy as that. If the user selects a menu item, it's just as easy. If the item has an Action event already, that is called. Otherwise, it calls a menu handler. If either of these return true, the event is handled and you're done at the point of returning true. However, if there's no Action or handler or they both return false, then the ContextualMenuAction event is fired and you are passed the MenuItem which was hit.
So not only is it a very powerful system which allows you access to the entire MenuItem API (something which ContextualMenu does not allow), it's correct in a cross-platform manner and easy to use!
Oh, and if you think you should use ContextualMenu for other, non-contextual uses (like when the user selects a PopupArrow), you should consider using MenuItem.PopUp instead -- that gives you full access to the MenuItem APIs as well.
So, can you see why I think the ContextualMenu control should be deprecated and removed from the default control palette?
I think there are plenty of things that need to be deprecated.
Aaron, while I understand your reasoning for deprecating ContextualMenu, I'm having some trouble understanding your explanation of how to replace it. Is this a proposal for a future means of accessing contextual menus based upon the exsting menu system? Is this a means of creating contextual menus that can be used now? How would these contextual menus add system-wide contextual menu items to the bottom of the menu?
@Scott -- this is a system that's already in place that you've been able to use for some time now.
As for system-wide contextual menus, I'm not certain what that refers to.
You might call me crazy on this one, but I think maybe you should come up wth a non-standard menu creator that is a cross between your rgular menu editor and your window editor. The editor would have each non-standard menu in it, a property editor, and a code editor.
Then, on your window editor, include an extra property to reference said menus.
The reason I call it non-standard is because of the other places it could be used: Dock and icon-based menus (Think "Yahoo Widget Engine" as an example) for OS X; and tray items for Windows. (Honestly don't know if Windows would have as many uses as the Mac, now that I think about it....)
I mean Finder contextual menus (either built into the OS or added by the user) that should be added to the bottom of the contextual menus for individual applications. These items are therefore available to all applications.
Ah, so you're not talking about items that you are adding to a contextual menu in the Finder. You are talking about OS-added items? Like what? This is the first I've heard of such a feature, and to be honest, it sounds rather suspect. How would the Finder have any clue how to manipulate data in *my* application? How does the information flow?
Aaron, that feature's been there for a while - they usually get installed in either the main library or the user library (in a folder called, appropriately enough, "Contextual Menu Items.") It's how apps like Toast install their system-wide CMMs.
What I think Scott is talking about (correct me if I'm wrong) is this feature, and it's not something I would even expect RB to handle. Something like that would have to be created in XCode, I think. And no, I'm still learning stuff, so there's no way I'd be able to tell you how to do this.
I have absolutely no idea how it's done -- maybe it's done automatically by the OS, maybe there's an API for it. All I know is that items I place in the Contextual Menu Items folder become available to all of my apps. These include plugins that I've purchased for favorite items, changing file permissions, browsing folders, pasting stored phrases of text, etc. This allows me to add commonly-used tasks to all of the apps on my system. If you want RB apps to act like other apps on Mac OS X, these items should appear.
That's not so important -- the easy use of contextual menus is more relevant. I'd like to see a code example of the mechanism you've described in RB for using contextual menus without the ContextualMenu control. I haven't used contextual menus yet and would like to see how it's done.
You guys are so smart, you make me feel a little deprecated.
Of course, that could just be the fish I had for lunch.
Scott, you are correct, there is an API to handle menu items to the Finder Contextual Menu. The menu items are created in a .plugin and added to the Library:Contextual Menu Items: folder. When you restart the Finder they show up.
If you are curious in the slightest the plugin uses CMPluginExamineContext to determine if the menu is to be displayed and what text to show. You then implement CMPluginHandleSelection to handle the selection.
In {shameless plug} Ugly Dockling we allow the user to click on a document or application in the Finder that creates an alias into a folder in the Application Support that the app, that mostly works in the dock, to display the shortcut via the dock menu. Our own implementation of the old OS 9 Favorites menu.
Aaron, I didn't know that you could create a contextual menu using the popup. That's pretty cool.
So riddle me this: How come when using the Popup method and selecting a menu item I have to click on the parent window to re-establish focus? This seems like a bug in my opinion?
BTW, using Tiger and RB 2006R4.
To answer my own problem. You shouldn't try to open two contextual menus at the same time. Bad things happen. :-)
@Scott -- it sounds as though what you're looking after would require a separate app, just like it would on Windows (well, a DLL, really -- but they're essentially the same thing). So I don't think that functionality is something required of MenuItem or ContextualMenu, really. Thanks for the explanation Bob.
@Scott -- an example would be to do this from ConstructContextualMenu of anything:
base.Append( FileQuit )
return true
Then, when you right click, you should see your quit menu on there. Selecting it will automatically terminate the application (since it calls the menu handler for it).
The this is with the contextual menu events is that I have not found the to reliably work with all controls on all platforms... And an XPlatform API that is not consistent in what works and what does not is worst than none IMO.
So I use menu Item.popup...
As you know I'm NOT a windows fan so you can attribute the next heresy down to that...;)
The Win standard of showing it in MouseDown is IMO wasteful and annoying...
For buttons it makes sense not to fire an action until MouseUp... allowing the user to change their mind or realize the clicked in the wrong place IS important because the action may be significant ...
But I can't remember every changing my mind about wanting the a contextual menu when right clicking... and if done by accident no harm done because you still can cancel the menu without making a selection.
By bring up the menu on MouseDown the UI feels snappier and it does save time... admittedly only a little but it adds up...
There is no reason why in this respect contextual menus (or popups of any sort) should behave like buttons.
This IMO is a case where the Mac UI has superior experience... and it's a lot of little things like that which matter ...
@Karen -- you're always welcome to your opinions, but your opinions don't make it any less of a bug with your app. It won't work as the user expects, and it won't work with keyboards, so to be honest, it'd be better to simply not have them at all in that case just due to the annoyance factor.
But, as you said, you don't care about Windows. ;-)