Before PFT I had never written a popup system that I was completely happy with. I still haven’t but the one I wrote for PFT is the closest I’ve come. Every UI popup in PFT works with the same popup system.
Coercion had the first popup system. It was super basic. One popup at a time and only over the whole editor. I used it for the settings page and the preset browser. Orange Gate’s popup system is slightly more powerful. The big new feature was that you can set the size and position of popups relative to another component. Orbit also uses Orange Gate’s popup system.
When I designed PFT’s popup system I focused on flexibility. I needed to be able to show lots of popup components in lots of different places. A PFT popup can be realigned, resized, and destroyed from anywhere. This was especially helpful for implementing close buttons like you see in the about page and the activation popup. The implementation also takes care of closing popups on mouse exits and mouse clicks.
At the top of the component hierarchy lives a class called PopupHost
that overlays juce::Component
s over the main editor. It also takes care of positioning them so that stay within the bounds of the UI. A reference to this popup host’s interface is passed to all of the child components.
I took some inspiration from the low level Windows APIs where you request a new window be created and get an HWND
(window handle) returned. You use the HWND
to set all of the properties on your window. When you create a popup The PopupHost
allocates some space for your popup and returns a Popup::Handle
. The handle is just an int but that’s not important and you should use it like you have no idea what it is. After creating the popup you can resize it, position it, set the content component etc by calling into the PopupHost
using the handle. This means popup components can resize and readjust themselves which is pretty cool.
To make interacting with the PopupHost
less annoying I wrote up a little helper class called PopupClient
. It basically just automates the process of getting a Popup::Handle
and passing it to the PopupHost
each time you want to change something about the popup. Small win that makes interacting with the PopupHost
a little bit less painful.
Things to figure out still:
– Clicking anywhere in the UI (except for on a popup) closes the popup. If you click on a component that also triggers a popup it opens another one right after closing the current one. Because mouse events are asynchronous I was never able to figure out a nice way to make sure this never happens.
– Creating popups still feels a little weird and awkward.
The code isn’t necessarily complete but if you want a good starting point to implement popups in your own JUCE application it’s here: Github