A mildly unexpected announcement on Jasper’s blog (a little earlier than hinted previously) that leads to this page on JDK 6.0 project unveils the first binary drop of Consumer JRE, or “Java SE 6 Update N” as it will be officially known. While the previous name was very catchy, the new name is very bland and generic (really, you couldn’t go with a letter more sexy than “N”?)
The naming aside, we finally get a chance to play with Nimbus. Surprisingly, the full class name is sun.swing.plaf.nimbus.NimbusLookAndFeel
(why not in javax.swing?) There are a few visual glitches, as expected from early access drops. Here is a sample screenshot of an internal frame:

As you can see, while the desktop pane has a nice gradient image, other visuals still need to be improved, including the title pane main button, the title pane horizontal line and unselected enabled checkboxes and radiobuttons (they are marked as disabled and do not respond to mouse events).
It’s not clear how the community should report bugs. The feedback section points to the Swing & AWT forum, while the changelist shows that internally created bugs use the ancient and not so trustworthy bug parade.
A few months ago i wrote about Mac-specific font policy in Substance look-and-feel that makes all Substance-powered Swing application pick the correct font sizes when running under Mac OS. In the past few days i’ve added a font policy for Gnome desktops (Ubuntu among the rest), following a bug report opened by one of the users.
It pretty much follows the implementation of GtkLookAndFeel in JDK 6.0, querying the gnome.Gtk/FontName
and gnome.Xft/DPI
desktop properties to honor both the default desktop font size and the custom DPI setting.
Here is how an application looks like when it runs under Ubuntu 7.04 with the latest 4.1dev drop of Substance:

Here is how the same application looks like under TSCu_Times font with base size 9 and 144DPI setting (the default is 96DPI):

Note that you don’t need to change anything in your application – Substance handles the font size computation on its own. In addition, it also picks up the desktop anti-aliasing settings when it runs under JDK 6.0 and later.
The first part of this series showed that it takes a little more than vector-based painting to make a look-and-feel resolution-independent. That part discussed two of the basic building blocks of high DPI support – alignment and baseline. This part is going to talk about borders.
Going back to my original post on high DPI support in look-and-feels, here is a screenshot of an internal frame under Vista configured with 144DPI (150% original setting):

While the visual elements appear properly scaled (fonts, check marks, title pane icons, scroll bars), the borders are not; all the borders in this screenshot are still 1 pixel wide. While it appears OK in this screenshot (since most of the monitors are still running on 100’ish DPI settings), the borders will almost disappear under a monitor that has 144DPI as the default setting. Here is a screenshot with correctly computed border widths:

As you can see, all the borders are properly scaled, including buttons, tabs, scroll bar, text field, combobox, combobox arrow button and checkmarks of checkboxes and radio buttons.
In addition to computing border widths under high DPI settings, there are two additional points to keep in mind. The first one is that the border insets must match the border width. You can no longer return Insets(1,1,1,1) from getBorderInsets() method when the border itself is painted with more than one pixel. The second one is that under larger widths, you need to change the painting bounds of the border itself. Here is a screenshot of a checkbox menu item with the checkbox border painted at (0,0):

As you can see, since the border width is three pixels, the outer border rims are clipped (since the border painting itself is clipped to the component bounds). In order to properly paint such a border, you need to offset it to half its width:

This offsetting also affects the border insets, which now should be at least border width and not half border width.
The next entry is going to talk about additional issues that are specific to the support of high DPI settings.
I first touched on the subject of resolution-independent Swing UIs and automatic support for high-DPI monitors about six months ago. This area has been pioneered by Karsten in his Looks family of look-and-feels. The code from Looks was used as a starting point of supporting resolution independence in Substance look-and-feel, and the last two versions provided the basic support, including automatic scaling of fonts, insets and other UI elements (such as check boxes, arrow icons, scroll bars and others).
When Mikael Grev has contacted me about two weeks ago about an article that he was going to write about the support for high DPI in his layout manager (MigLayout), he has provided a long-needed push for me to resume working on this part of Substance (thanks, Mikael). So, what was missing?
Quite a lot, actually, and the past two weeks have seen numerous improvements in this area across all the core Swing components. In this part, i’m going to talk about two area, alignment and baseline.
The first support for these two areas under Substance was introduced in this blog entry that showed how text components, combos and spinners have the same height (alignment). In addition, the inner texts are aligned as well (baseline). Here is a screenshot from that entry:

As it turns out, this is not an easy thing to achieve even for a fixed font size. To understand why, you need to understand how comboboxes and spinners are implemented.
- Text components (JTextField, JFormattedTextField, JPasswordField) are simple – they have a border, insets and the actual document that is displayed. The component bounds are computed from the document size and the insets.
- Non-editable comboboxes are more complicated. They have border, insets, arrow button and a cell renderer that shows the selected value. The cell renderer by default is a label with insets. The component bounds are computed from the label size, label insets, the combo insets and button bounds.
- Editable comboboxes have border, insets, arrow button and a text field (editor). The text field also has border (in most cases it would a non-painting one) and insets. The component bounds are computed from the text field document size, text field insets, the combo insets and button bounds.
- Spinners have border, insets, up button, down button and a text field (editor). The text field also has border (in most cases it would a non-painting one) and insets. The component bounds are computed from the text field document size, text field insets, spinner insets and button bounds.
So, how do you get all these components have the same height and the same text alignment? That’s the black magic of playing with the pixel insets in each one of the UI delegates. To get a small taste of what it feels like to be a look-and-feel developer, see the this source file from the Looks package.
And now imagine taking that implementation and scaling it to arbitrary font sizes (click the image to see more font sizes):

Now that is a whole new challenge – how to compute the insets of all the inner parts of comboboxes and spinners so that they scale with the resolution settings and remain globally aligned. Not to mention that the texts need to be aligned as well – here is a screenshot of three component rows under font sizes 22, 23 and 24 pixels (click to see full-size image):

Stay tuned for the next part when i will talk about scaling other visual parts of Swing UIs. Once again, thanks to Mikael for the challenge :)