Recently I wrote about a few simple tricks that make it possible to display more than just text in a StyledText widget. In this article I take it a step further: displaying images in an SWT StyledText widget.
Normally a StyledText widget cannot display images. Why would you want to display images in a text control, you might ask? Well, there are cases where a rich text control is used to render text which may have embedded images. Take for example the Mylyn task editor. It displays bug descriptions and comments. In some repositories (such as Trac or JIRA) it's possible to use markup to display rich text and images. It's common to see screenshots or other visual data included in bug reports.
To display images in a StyledText we use a small variation on the tricks from my previous post. Previously I used an annotation to mark the location of the thing I wanted to draw, and a painter to paint it. This approach works well when we know the size of the thing we're about to draw (such as a character or horizontal rule). In the case of images, it gets more complicated. We need to know the size of the image so that we can create enough space for it in the text.
Since loading image data can be slow (over a network or from a busy disk) we must load the image asynchronously and render it when it becomes available. We can get away with it since users are used to this experience -- that's how web browsers work.
So here's a run-down of the technique I used:
- Mark the location of the image with an annotation
- Asynchronously download the image
- When the image becomes available, determine its height (in pixels)
- Determine the font in use at the annotated location
- Using font metrics compute the number of blank lines required to create enough vertical space (in pixels) to display the image without obscuring text
- Insert the required number of newlines into the text widget
- Adjust text presentation offsets (some styled regions may need to be translated by the same number of characters as we inserted in the previous step)
- Associate the image data with the annotation so that the painter will have access to it
- Cause the text widget to repaint
- Use the custom painter to paint the image in the empty space that we created
Here's a screenshot demonstrating this technique in action:It works! The SWT StyledText can now display images!
Though the result is pleasing, there remain a few issues with this approach:
- Images don't flow with the text, that is we can't wrap text around the image on the left or right side, only above and below.
- Images aren't included in clipboard operations such as copy and paste.
If you're interested in the code involved in this technique you can find it here.
The fact that we can do this using standard JFace and SWT APIs is a testament to the quality and completeness of the platform. Thanks Eclipse!