DragAndDropContainer::setCurrentDragImage and Retina displays

Is there any way to specify a scale factor for DragAndDropContainer::setCurrentDragImage ?
If not, can you add a new parameter?
setCurrentDragImage (Image img, int scaleFactor = 1.0) ?

Thanks!

1 Like

Why not just give it a resized copy of the image?

Hi Jules!

yes, is what Iā€™m doing, but the dragged image is not ā€œhigh resā€, I get a blurry version instead.

dragImage = createComponentSnapshot (getLocalBounds(), true, scale).convertedToFormat (Image::ARGB);
dragImage.multiplyAllAlphas (0.8f);
drag->setCurrentDragImage (dragImage. rescaled(getWidth()/2, getHeight()/2));

the same:

dragImage = createComponentSnapshot (getLocalBounds()).convertedToFormat (Image::ARGB);
dragImage.multiplyAllAlphas (0.8f);
drag->setCurrentDragImage (dragImage);

What I want:

dragImage = createComponentSnapshot (getLocalBounds(), true, scale).convertedToFormat (Image::ARGB);
dragImage.multiplyAllAlphas (0.8f);
drag->setCurrentDragImage (dragImage, 1/scale);

Is not something that worries me so much, but it would be better to be able to see the dragged image ā€œhi resā€ as the whole gui.

Cheers!

Huh? How do you imagine that the dragger could magically draw a higher-resolution image than the one you give it?

Jules, I donā€™t imagine that, my english is not good, I think i have explained myself wrong.
the result of the two first pieces of code Iā€™d posted before (whitout multiplyAllAlphas):

Component:

Dragged image of the component

the dragged image is blurry, I want to keep the same ā€œhi resā€ for the dragging image, my original question is if there is any way to do that.
Thanks

If you want a higher resolution image, render it at a higher resolution!

If setCurrentDragImage had a scale factor, all that it could do would be to call rescaled on the image you gave it, which is the same thing youā€™re doing. Itā€™d be impossible for it to somehow make the image higher-resolution than the one you pass in.

Itā€™s what Iā€™ve done at the first try (scale = 2.0):

dragImage = createComponentSnapshot (getLocalBounds(), true, scale).convertedToFormat (Image::ARGB);

But when I set the image drag->setCurrentDragImage (dragImage) I get a double size draggingComponent (or image) than the original component.

The paint method in DragAndDropContainer::DragImageComponent draws the image with g.drawImageAt (image, 0, 0);, but to get a ā€œā€ā€œretina super resolutionā€ā€œā€ I need to pass to setCurrentDragImage a double size image createComponentSnapshot (getLocalBounds(), true, 2.0) and then draws it with:

    scaleFactor = 1/scale;
    g.drawImage (image, 0, 0, image.getWidth() * scaleFactor,
                 image.getHeight() * scaleFactor,
                 0, 0, image.getWidth(), image.getHeight());

Ok, I modified the DragImageComponent::paint method and hardcoded the scalingFactor, And it works fine.
Maybe there is another simple way to make it retina compatible but I donā€™t know
Without setting the drag image (passing nullptr image to DragAndDropContainer::startDragging) it does not work either, I get a blurry dragging image.

1 Like

What @xeneize is saying, and I bet you already understood it yourself, is that the component snapshot that is drawn drag image is always rendered with one pixel of the image mapped to one logical point of the screen (which corresponds to TWO physical pixels on retina displays).

This gives the expected result in ordinary displays that have 1 physical pixel per logical point, but is problematic on retina displays where there are two physical pixels per every single logical point.

On retina displays, then, one of the following two problems arise:

  • If the Component snapshot is taken at retina resolution (scale = 2), then the resulting image dimension in physical pixels is double the dimension of the Component bounds.
    Now, because the drag image is always drawn with one image pixel per logcial point (stated above), this results in an image that occupies twice the area of the Component on the screen

  • If the Component snapshot is taken at non-retina resolution (scale = 1), then the resulting image dimension in pixels will equal the Component bounds, but since each pixel of the image is drawn to one logical point, and one such point occupies two physical pixels of the screen, the net result is that each pixel of the image is drawn on two pixels of the screen, which gives the blurry, non-retina look to the result, albeit at least resulting in an image that occupies on the screen the same size of the Component it represents.

I think that adding a scale member to Image should be considered. One such member would effectively convey the information of how many pixels of the image should be mapped to each logical point, which is an information that inherently belongs to the Image itself and would instruct all paint routines on how to deal with the image.

If you are dubious about whether that is a useful approach, let it be know that I have wrapped my own RichImage class around the juce::Image class exactly to add that feature, and have used it since years now without a regret about its design.

Yup.

TBH the best plan would probably be for this to use a Component instead of an image, so that thereā€™s no need to faff around with scale factors. Weā€™ll take a look and see if thereā€™s something nice we can do.

1 Like

@yfede great explanation, thanks :slight_smile:
@jules I think it would be a good solution, So that you can handle/draw it as you want.

Thanks!

DragAndDropContainer still generates a blurry image by default.
Is there any workaround to get a crispy image at the right size on retina?

would be lovely!

1 Like

Any chance you could take a look at this sometime ?
I would not insist or care that much if there was a workaround, but currently there is no other alternative (as far as I can see) than modifying the juce codeā€¦ :scream:

so at the moment we got to modify DragImageComponent::paint() locally

void paint (Graphics& g) override
{
    if (isOpaque())
        g.fillAll (Colours::white);

    g.setOpacity (1.0f);

    auto scale = Desktop::getInstance().getDisplays().findDisplayForRect (getScreenBounds()).scale;
    g.drawImageTransformed (image, AffineTransform::scale (1.0f / (float) scale));
}

anything planned about that?

Sorry, weā€™ve not had time to think about this one yetā€¦

Hi,
I am running into the same issue.
Any news on this?

unfortunately not.
this still bothers me everytime I implement some drag-and-drop and I modify DragImageComponent::paint() locally to fix that.
I had added it to the features requests category (here) but I probably shouldnā€™t have, as this is rather a bug to fix than a FR imo
(I guess the juce team didnā€™t fix it yet because the fix is most likely likely be a breaking change : without a code update the resulting image would be smaller)

1 Like

Coming up on 5 years now. Any news on fixing/workaround for this yet? The blurry drag image looks really bad!!

hi @mattingalls
thereā€™s an fr about it here if you want to upvote it :slight_smile:

1 Like

Iā€™ve made some changes to the DragAndDropContainer to allow dragging an oversampled image:

This should resolve the blurriness you were seeing. Please try out the change and let us know if you encounter any issues.

1 Like

Works for me. Looks a lot better. Scaled cursors also working as well.

1 Like