PopupMenu/ContextMenu and Tranforms


#1

I had the idea to use JUCE' Component's neat setTranform() to implement a quick and dirty resize feature inside my audio plug-ins.

Inside the plugin editor, I do the following...

    if( mode == 0 ) // normal size
    {
        setSize ( originalWidth, originalHeight );
        setTransform( AffineTransform::identity );
    }
    else // double size
    {
        setSize ( originalWidth * 2, originalHeight * 2 );
        setTransform( AffineTransform::scale( 2.0f ) );
    }

...which - to my surprise, works great. All fonts, hand-drawn elements, as well as bitmaps scale perfectly (at least for my purpose).

 

The only problem is the fact that PopupMenus aren't derived from Component and thus do not support tranforms at all. I searched throught the documentation and found this:

"Currently, transforms are not supported for desktop windows, so the transform will be ignored if you put a component on the desktop."

Ok. But as far as I can see, this implies that Comboboxes, even if they formaly support transforms, are not cappable to draw their own PopupMenu element properly?

The only fix I found is awkward (tricking the component to think that the original component has say, the double size than it really has; after hours of hacky jedi trickery). The tooltips on the other hand need a specific lookandfeel class for every possible size.

Now my question is simple: Why can't JUCE just derive anything "Popup" from Component (which would perfectly fine from the oop point of view)?

...or is there another way to achieve the same with the latest JUCE version? (maybe a mysterious setting telling JUCE that I don't want to draw my popupmenus on the desktop anyway?) The transforms seem to be the perfect tool for user controlled UI resizing. But the popup problem is truly a show-stopper for me. I really don't want to write my own elementary UI classes from scratch just because of that minuscule "missing feature" (which in the case of comboboxes smells more like a bug to me  ;)).


#2

It can now apply a scale to desktop objects - have a look at Component::getDesktopScaleFactor()


#3

Thanks you Jules, I'll give it a try! I totally oversaw the desktop scaling methods...


#4

Ok, after realizing that JUCE already offers a global scaling mode.. ;) ..I tried this:

    if( mode == 0 ) // normal size
    {
        setSize ( originalWidth, originalHeight );
        Desktop::getInstance().setGlobalScaleFactor( 1.f );
    }
    else // double size
    {
        setSize ( originalWidth * 2, originalHeight * 2 );
        Desktop::getInstance().setGlobalScaleFactor( 2.f );
    }

At first, this seemed to work great (in VSTAnalyser). Until I found out that the host crashes under certain conditions. It always works fine initially (first call). I can't debug the crash properly, it's an unhandled exception in juce_Win32_Windowing.cpp getWindowRect (HWND hwnd).

To be clear, this works perfectly fine:
 

    if( mode == 0 ) // normal size
    {
        setSize ( originalWidth, originalHeight );
    }
    else // double size
    {
        setSize ( originalWidth * 2, originalHeight * 2 );
    }

or even:

    if( mode == 0 ) // normal size
    {
        setSize ( originalWidth, originalHeight );
        Desktop::getInstance().setGlobalScaleFactor( 1.f );
    }
    else // double size
    {
        setSize ( originalWidth * 2, originalHeight * 2 );
        Desktop::getInstance().setGlobalScaleFactor( 1.f );
    }

(this specific code gets called within an ActionListener handler inside the pluginEditor)


Now, to complicate things further, the subject behaves totally differently in Reaper. Here, the host seems to interpret setGlobalScaleFactor() in addition to pluginEditor.setSize(), effectively quadrupling the plugin window. No crashes at all here, just the weird scaling behavior.

 

Before making the diskussion too complicated, let me explain my goals: User defined UI scaling of a plugin editor in a simple and generic manner.

Jules, maybe you can elaborate a bit on the behavior of setGlobalScaleFactor() and how it could interact with pluginEditor.setSize()? Seeing the very different reactions of plugin hosts to setGlobalScaleFactor(), in particular in conjuction with pluginEditor.setSize(), I am really unsure if this is really the best approach to solve this specific task.


#5

To be honest, the global scaling factor stuff was only designed and tested for apps.

In a plugin, the host will expect the plugin windows to report their size and position using normal desktop units, so if you mess with the coord system so that the host and plugin are talking in different scales, then things will inevitable go a bit screwy.

It *might* be possible to make the global scale work as long as the plugin wrapper classes were modified to force them to always ignore this and use a scale of 1.0 (by overriding Component::getDesktopScaleFactor() for any windows they create). Then you could re-scale the plugin UIs by using a transform on your internal component, but still get global rescaling of menus, etc. I've no time to try that, but you may want to experiment..


#6

Oh well, it's good to know I'm moving on insecure ground. I'll experiment and keep you udated if I find a good solution or maybe the source of the problem. Thank you for the assistance so far!