PopupMenu scaling issue on Windows HiDPI

Hi all,

I’m experiencing a problem with PopupMenu on a HiDPI-screen on Windows. The plugin itself is scaled correctly, but when I show my popup menu, it’s tiny, abviously not being scaled up for HiDPI. Am I missing anything obvious here? I don’t think I’m doing anything crazy, just calling PopupMenu.show() in a button listener. The menu itself is also working, it’s just a scaling issue.

I must admit that being relatively new to JUCE, trawling the forum for threads on this topic is more confusing than helpful, because similar issues have apparently been happening in older versions of JUCE, but it’s hard to tell what the status quo is, so that being said, after having used the search function, I’d appreciate any nudges in the right direction :slight_smile:

1 Like

How did you get your copy of JUCE? I’d recommend rebuilding with the current version of JUCE’s develop branch and checking whether the problem still persists.

If you still see the same problem, it would be useful to see a small code example so that we can attempt to reproduce the issue.

I’ll provide details later, in a bit of a time crunch pre-public beta, but apparently I just “fixed” the bug by using showAt() instead of show(). DAW is Reaper 6 with HiDPI enabled on win 10 btw.

@reuk The same issue occurs with tooltip windows. We’re using JUCE 6.0.8 from the master branch.

Yeah this is a real issue, I unfortunately had to go through and remove all .show() code to use showAt() with a parent. There’s no way to pass an affine transform to the show method, where it will match the transform on the parent with showAt() it’s a bit of a pain because free floating popup menus are not usable with scalable UIs – And DAWs like Reaper on Windows show it miffed up no matter what if it’s not attached to a parent

1 Like

How would I do that with TooltipWindow (or a component derived from TooltipWindow) though? There is no show() I could replace with showAt()…

1 Like

Here’s a couple solutions I came up with which helped sort it out – they’re not ideal but if fixes the problem:

For tooltips:

Make sure you’re passing your editor into the constructor:

TooltipWindow mTooltipWindow { this }; in your editor

Unfortunately it means you can’t use shared resource pointer, but its the lesser evil.

For Popups which you want to have “free float” under your mouse where it’s pressed I’ve done:

        Component scale_control;
        scale_control.setBounds(event.x, event.y, 0, 0);
        addChildComponent(scale_control);
        const int result = m.showAt(&scale_control);

essentially, what you’re doing is adding a little invisible component which will result in the scale factor being computed properly, without needing to render the popup under a component. It’s ugly but fixes the problem.

1 Like

I’ve had a chance to look at this a bit, and I think that the popup menu behaviour is by design.

In a plugin, the scale of the UI is normally controlled by the DAW. The DAW is allowed to set a different scale factor on each plugin window. This means we need to query the current AudioProcessorEditor (or one of its child components) for the current scale before drawing a PopupMenu.

On a related note, I would strongly advise against using either PopupMenu::show or PopupMenu::showAt. These functions are modal, and are very likely to cause problems in your plugin. Instead, use PopupMenu::showMenuAsync. This allows you to pass an Options structure with a separate target component and screen area.

const auto mousePos = Desktop::getInstance().getMousePosition();
const auto targetArea = Rectangle<int>{}.withPosition (mousePos);
menu.showMenuAsync (PopupMenu::Options{}.withTargetComponent (this)
                                        .withTargetScreenArea (targetArea));

In this way, you should be able to show the menu at a specific location and with the correct scale, without needing to add any additional intermediate components.

3 Likes

derp. testing.

For the TooltipWindow issue, I think we can probably make a change in JUCE so that the TooltipWindow will always derive its Desktop Scale Factor from the scale factor of the hovered component. This should mean that it’s possible to hold a TooltipWindow in a SharedResourcePointer and have it scale appropriately, even when the host chooses to display multiple plugin windows at different scale factors. This change is still in testing, I’ll update this thread if we decide to push this change.

2 Likes

That’s great to hear and it brings me to a potential follow-up question on a related note:

For a plugin that uses an additional global scale factor in the top level editor via juce::Desktop::getInstance().setGlobalScaleFactor(scaleFactor);,
would it be possible to give the tooltip windows a custom scale factor? I assume no, and it wouldn’t be the end of the world. The reason I’m asking is the following: The code I’m working with is not my original code and for a custom component I developed, I added functionality to make it scale itself and its child components by an inverse scaling factor, to appear at 100% scale, even if the plugin editor uses a (fixed) 85% scaling.

I think we’re unlikely to add a custom scaling parameter directly to the TooltipWindow, but you should be able to get the same effect by deriving from TooltipWindow and overriding Component::getDesktopScaleFactor.

I’ve added auto-scaling TooltipWindows here:

1 Like

Awesome, thanks a lot for the quick turnaround. Any projections on this being merged to master?

Also, while I have you here, we’re seeing the same behaviour with custom cursors (cursor image being drawn at 50% scaling on HiDPI screens on Windows). I assume this has the same root cause, a cursory (erm…) glance through the forum revealed no current topics dealing with this, so two questions:

  • Should I create a new thread for that issue or keep the discussion here?
  • Can you look into this, going on the assumption that it’s a similar scenario as with TooltipWindow?

Best,
Andreas

I expect this’ll be on master in a few weeks.

A new thread will allow us to gauge the interest in adding this particular feature, so I’d recommend doing that.

I’m not sure this assumption holds. For tooltips, we can assume that the tooltip needs to display at a scale that’s related to the thing being hovered. For cursors, I think we’d need to use a different technique to find the correct scale. In addition, cursors aren’t standard Components, so we’d need to handle the scaling itself differently. I’m less experienced with the MouseCursor code than with Component, so it’s difficult to estimate how long this work would take.

1 Like

mumu from the juce forum is the gift that keeps on giving

1 Like