-
Notifications
You must be signed in to change notification settings - Fork 863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid remaining trivial uses of new ImageIcon(Image), for HiDPI icons #8109
base: master
Are you sure you want to change the base?
Conversation
Replace most of the remaining trivial uses of the ImageIcon(Image) constructor, replacing these with ImageUtilities.image2Icon or ImageUtilities.loadImageIcon. This allows SVG icons, when/once present, to render in full resolution on HiDPI/Retina displays. Bitmap icons also benefit from the improved scaling hints applied by ImageUtilities. Similar work was done, for the platform module only, in apache#7472 . This commit covers most of the remaining trivial cases; I grepped the codebase for 'new ImageIcon' and adjusted the code to avoid ImageIcon whenever this could be done easily (not changing APIs, requiring only a visual code review).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks sane to me. Only eyeballed though. There is more cleanup possible, but that is a different task.
Thanks! I will run with this in my working IDE for a few days before merging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got confused at the end so excuse if anything I commented on makes no sense ;)
some notes:
- i think this PR would have benefited from 2 commits, one which refactors loading, the other which refactors conversion/wrapping problems
- nitpick but most of the
, false)
postfixes could be probably removed, since most of the original code did also use the overloaded variants which set it to false by default.
@@ -108,60 +107,47 @@ public static ImageIcon getElementIcon( ElementKind elementKind, Collection<Modi | |||
modifiers = Collections.<Modifier>emptyList(); | |||
} | |||
|
|||
Image img = null; | |||
ImageIcon icon; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move this line into the CONSTANT
case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. (Declarations in a case statement will leak to the subsequent cases, so I left it at the top. But either style works.)
private ImageIcon getImageIcon(String name, boolean error){ | ||
ImageIcon icon = ImageUtilities.loadImageIcon(name, false); | ||
if(error) | ||
return new ImageIcon(ImageUtilities.mergeImages( icon.getImage(), ERROR_IMAGE, 15, 7 )); | ||
else | ||
private Icon getIcon(String name, boolean error){ | ||
Icon icon = ImageUtilities.loadImageIcon(name, false); | ||
if (error) { | ||
return ImageUtilities.image2Icon(ImageUtilities.mergeImages( | ||
ImageUtilities.icon2Image(icon), ERROR_IMAGE, 15, 7 )); | ||
} else { | ||
return icon; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one call less if the variable keeps the original ImageIcon
type.
private Icon getIcon(String name, boolean error){
ImageIcon icon = ImageUtilities.loadImageIcon(name, false);
if (error) {
return ImageUtilities.image2Icon(ImageUtilities.mergeImages(icon.getImage(), ERROR_IMAGE, 15, 7 ));
} else {
return icon;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's another change I think can be dropped overall since mergeImages is smart enough to preserve HiDPI resolution.
ImageIcon imageIcon = new ImageIcon(DataObject.find(fo).getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)); | ||
icon = ImageUtilities.image2Icon(DataObject.find(fo).getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)); | ||
Boolean inTestFile = ElementGripFactory.getDefault().inTestFile(fo); | ||
if (Boolean.TRUE == inTestFile) { | ||
Image mergeImages = ImageUtilities.mergeImages(imageIcon.getImage(), | ||
ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/java/resources/found_item_test.png", false).getImage(), 4, 4); | ||
imageIcon = new ImageIcon(mergeImages); | ||
icon = ImageUtilities.image2Icon(ImageUtilities.mergeImages(ImageUtilities.icon2Image(icon), | ||
ImageUtilities.loadImage("org/netbeans/modules/refactoring/java/resources/found_item_test.png", false), 4, 4)); | ||
} | ||
icon = imageIcon; | ||
} catch (DataObjectNotFoundException ex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar here. I think ImageIcon icon
would allow to skip the call to icon2image
.
although the lookup registration later would have to be changed to icon.getImage()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can simplify it a bit here; keeping the ImageIcon from loadImageIcon while keeping image2Icon instead of the "new ImageIcon" constructor.
ImageIcon imageIcon = new ImageIcon(DataObject.find(fo).getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)); | ||
Icon icon = ImageUtilities.image2Icon(DataObject.find(fo).getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16)); | ||
Boolean inTestFile = ElementGripFactory.getDefault().inTestFile(fo); | ||
if(Boolean.TRUE == inTestFile) { | ||
Image mergeImages = ImageUtilities.mergeImages(imageIcon.getImage(), | ||
ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/java/resources/found_item_test.png", false).getImage(), 4, 4); | ||
imageIcon = new ImageIcon(mergeImages); | ||
icon = ImageUtilities.image2Icon(ImageUtilities.mergeImages( | ||
ImageUtilities.icon2Image(icon), | ||
ImageUtilities.loadImage("org/netbeans/modules/refactoring/java/resources/found_item_test.png", false), 4, 4)); | ||
} | ||
return imageIcon; | ||
return icon; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
return ImageUtilities.mergeImages(original, ProjectProperties.ICON_BROKEN_BADGE.getImage(), 8, 0); | ||
return ImageUtilities.mergeImages(original, | ||
ImageUtilities.icon2Image(ProjectProperties.ICON_BROKEN_BADGE), 8, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this change needed?
the utility method will simply call getImage() anyway, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some custom handling for certain Icon subclasses, but reading over the ImageUtilities code, it indeed seems that the change is unnecessary! mergeImages is smart enough to preserve vector graphics in these cases.
I will remove the changes around mergeImages.
return ImageUtilities.mergeImages(original, ProjectProperties.ICON_BROKEN_BADGE.getImage(), 8, 0); | ||
return ImageUtilities.mergeImages(original, | ||
ImageUtilities.icon2Image(ProjectProperties.ICON_BROKEN_BADGE), 8, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same question
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, I'll remove these from the patch, as mergeImages is smart enough to avoid the need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
many instances where imageicon.getImage()
was changed to icon2image(imageicon)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, will remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here too. getImage() was changed to icon2Image()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to reduce the use of ImageIcon, as it assumes that icons are bitmaps rather than vector graphics. When ImageIcon is used it's harder to reason about whether vector graphics will be preserved or not.
Thanks for useful reviews!
I see now that the changes around mergeImages can probably be removed, since mergeImages is smart enough to pick up the special implementations of Image and Icon by itself.
ImageUtilities has loadImage(String) and loadImage(String,boolean) but no loadIconImage(String), only loadIconImage(String,boolean). I think I will make a separate PR with some proposed new methods in ImageUtilities that can simplify some of these changes:
|
I proposed some new utility methods for ImageUtilities in #8114. One of these will let me change "loadImageIcon(path, false)" to just "loadIcon(path)" in most of the cases here. |
In previous PRs, e.g. #7463 and #8083, SVG versions of various NetBeans icons were added to look better on Retina/HiDPI monitors. ImageUtilities has supported automatic loading of SVG versions of icons since #1278 .
To render at full HiDPI resolution, Icon/Image instances must be created via the methods in ImageUtilities rather than, in particular, the constructors of ImageIcon. Uses of the latter must be replaced with e.g. ImageUtilities.image2Icon and ImageUtilities.loadImageIcon. Some such replacements were done in #7472 .
This PR replaces most of the remaining trivial uses of the ImageIcon(Image) constructor. This allows SVG icons, when/once present, to render in full resolution on HiDPI/Retina displays. Bitmap icons also benefit from the improved scaling hints applied by ImageUtilities.
While this PR touches many lines, the changes should be simple enough that they can be reviewed by simply reading over the diffs (rather than by opening every dialog, UI panel etc. in a running IDE). I will also run my working IDE with these changes for a while to see if I bump into any observable problems. It's not necessary to have a HiDPI screen to test this patch; merely seeing that there are no new exceptions etc. when running the IDE should be sufficient.
There are still many uses of the "new ImageIcon(String)" and "new ImageIcon(URL)" variations of the ImageIcon constructors. Removing these is left for future work.