December 21, 2023

the context menu

With the library up and running, there’s one last thing we need to support as much functionality as possible: the humble context menu.

Getting pretty good at this widget thing.

With valuable experience gained building out the library UI, I decide to tackle context menus. There is the usual time spent figuring out how to get the data out of Rack. I catalog the types of entries that can be in a menu: labels, dividers, booleans, ranges, submenus, etc. I come up with a scheme for telling Rack which menu or submenu I want, given menus are created on the fly and don’t have anything like an ID. It ends up resembling a linked list where I keep track of which menu items beget further (sub)menus, then move up and down that chain to find what I’m looking for. I learn how to spawn a context menu in Rack and then fake mouse input to interact with it.

Working out how to handle menu dividers.

At this point, nearly a year out from the start of this project, I’m starting to feel pretty confident in my knowledge and abilities. Building out the context menus goes remarkably smoothly and before long I have them fully functional.

Why are context menus a big deal? Here is an example:

Rack on the left, Unreal on the right. Notice anything missing?

As I’ve mentioned before, some of the graphics in Rack are handled by plugin authors dynamically drawing things at runtime, as exemplified by the LCD above. And, as you can see, I am not (yet, maybe ever) supporting those dynamic graphics. There are two things that can help mitigate the missing information from the display. One is meaningful data in the tooltip for the related controls. Unfortunately, as is the case in this example, plugin authors often neglect to provide good labels in the tooltips. You can turn that knob all you want but the only feedback you’ll have is the numeric value used internally being shown in the tooltip. Without a meaningful tooltip, we have to hope that the options present in the encoder/display combo are also present in a context menu. And they often are! Here’s the context menu for that module, thank goodness:

No dynamic graphics, no problem. For this module, anyway.

The last, maybe most important reason we need context menus is the Audio and MIDI modules:

Without the context menus, it’d be impossible to select your audio output device and such or set up MIDI controllers. This also leads to the second necessary modification to Rack’s code: the menu above is not the standard context menu. It’s a separate menu spawned by clicking somewhere else on the module. Rather than trying to code in exceptions for those menus, and figure out how to spawn them on the Rack side, I have simply modified the Rack implementation to dump those menu options into the standard right-click context menu. Thankfully the Rack developers have provided methods to do precisely that, for any other plugin authors who might want to use the audio or MIDI device menus.

With that, we have another major component of Rack’s user experience in place, and this thing is damn near usable. Incredible.