If you’re interested in knowing more about Substance internals, this post is for you. It is a rather advanced topic, and it assumes a certain level of familiarity with how Swing internals work in general. Here is a list of overview articles that provide a glimpse into how Swing operates:

The rest of the post assumes that you’re familiar with the basic building blocks of Swing painting pipeline and common terms of UI delegates.

Contact points

As a UI toolkit, Swing takes care of displaying the application UI controls as pixels on the screen, and handles the user interaction with those pixels. This process has many steps, most of which can be configured by the application via custom painting, layered panes, glass panes and more. Applications that do not use these extension points rely on the current look-and-feel to put the pixels on the screen and control certain aspects of the user interaction.

A look-and-feel is a collection of UI delegates. Each UI delegate handles the specific Swing component type – buttons have button UI delegates, sliders have slider UI delegates, etc. While each component type is different, the UI delegates have very similar contact points that control the various aspects of component lifecycle. Here is the list of major contact points:

  • Configuring the visual settings. This includes colors and fonts.
  • Configuring the inner layout metrics. This includes insets, margins and gaps.
  • Computing the preferred dimension.
  • Layout of inner components for composite controls. This is relevant for controls such as combobox which has an inner text field and arrow button.
  • Listening to component’s model changes. This includes mouse and keyboard, as well as change and item listeners – depending on the specific control type.
  • Painting the different visual areas.

As you can see, painting is only one contact point among many. In an ideal model-view separation promoted by the core Swing library, the UI delegate is responsible for anything that is related to the component’s visual and interaction facets.

Why choose Substance?

Why would you want to use a third-party look-and-feel when core Swing has a number of bundled look-and-feels (including the addition of Nimbus in 6u10+)? Subjective preferences about the visuals aside, Substance provides the following features one would expect from a modern UI toolkit:

  • Full high DPI support for the core Swing controls with resolution-independent painting.
  • Respecting the desktop font settings of the current environment.
  • Built-in animations for the core Swing controls (rollover, selection, …)
  • Skinning layer, and especially decoration areas. The eventual goal is to enable even the most demanding designs to be implemented as self-contained Substance skins that can be ported across different applications in the same portfolio.

Substance implementation

As a high-level view, the following Substance classes address the four main points above:

  • <span style="color: darkblue;">SubstanceSizeUtils</span> has a bunch of methods to compute the different metrics based on the component font size. It makes sure that all the component visuals (borders, gaps, margins, insets, …) scale and result in consistent physical appearance on various hardware.
  • <span style="color: darkblue;">SubstanceFontUtilities</span> has font policy implementations for Windows, Gnome, KDE and Mac desktops.
  • <span style="color: darkblue;">FadeTracker</span> (to be refactored to use Trident in the next major Substance version) is the animation engine that powers all built-in animations.
  • <span style="color: darkblue;">SubstanceSkin</span> and <span style="color: darkblue;">SubstanceColorSchemeBundle</span> are the main classes in the skinning layer.

Each Substance UI delegate uses these four classes at different contact points:

  • <span style="color: darkblue;">SubstanceSizeUtils</span> is used during the initialization to set up gaps, margins and insets. It is also used during the painting to compute border weights, and in the layout managers to compute the preferred sizes and layout internal sub-components.
  • <span style="color: darkblue;">SubstanceFontUtilities</span> is used to populate the <span style="color: darkblue;">*.font</span> entries in the <span style="color: darkblue;">UIManager</span> that are later used to set the fonts on the components during the initialization stage.
  • <span style="color: darkblue;">FadeTracker</span> is used in various mouse / change listeners to initiate animation sequences (such as mouse rollover over a button, tab losing selection state) and during the painting to show cross-fades between the states.
  • <span style="color: darkblue;">SubstanceSkin</span> is used during the painting to compute the colors for painting the different visual areas of the component.

Supporting wide variety of font sizes in modern UI toolkits is a necessity, and previous entry provided a little background on the topic. The keen-eyed readers might have noticed the gaps in the curved corners of the combobox arrow button:

What happened here? The border painter in Substance gets two contours – the outer and the inner. For buttons, these contours are computed by matching the button shaper, ClassicButtonShaper in case of combobox arrow buttons. The problem in the computation was that it used the same curvature radius for both outer and inner contours, which resulted in the visible visual gaps under large font sizes.

The correct solution is to subtract the border stroke weight from the outer radius, and use the resulting value for the inner radius. Unfortunately, the API signature of the SubstanceButtonShaper interface had to be changed in order to accommodate this functionality – so if you have a custom button shaper, you will need to implement a new method added to this interface.

The following screenshot shows a large checkmark icon under Substance 5.2dev (on left) and Substance 5.1 (on right):

https://substance.dev.java.net/release-info/5.2/inner-controur-radius-checkmarks.png

The next screenshot shows a combobox under Substance 5.2dev (on top) and Substance 5.1 (on bottom):

https://substance.dev.java.net/release-info/5.2/inner-controur-radius-combos.png

As you can see in both screenshots, the inner contour is now aligned with the outer contour in the corners.

This work will continue in the next releases to make sure that all core Swing controls look correctly under different font sizes, including very large values such as shown in this entry. In the meantime, you’re welcome to take the latest 5.2dev drop of core Substance (code-named Quebec) for a spin. Release candidate for Substance 5.2 is scheduled for May 11 and the final release is scheduled for May 25.

The decoration areas in Substance look-and-feel are, in my view, one of the more powerful features of the library and allow to programmatically implement even the most demanding visual designs in a well-structured way. The lifecycle of Swing UI delegates is not very well suited to using different foreground and background colors on components of the same type in different parts of the same window, and implementing this properly without affecting the performance is an interesting challenge.

The latest binary drops of Substance 5.2dev (code-named Quebec) provide much better support for renderer-based components, such as lists, tables and trees when these are placed in custom Substance decoration areas. To illustrate this, here is a screenshot of a sample application under Substance 5.1 Business Black Steel skin:

There are four different decoration areas, each having one enabled and one disabled list. The visuals are quite jarring – the contrast between even and odd rows (striping) is too high, and the foreground color of odd rows in the top-left enabled list is black (on black background). Here is how the same app looks under Substance 5.2dev:

The next screenshot shows a sample application with tables under Substance 5.1 Business Blue Steel skin:

In addition to the same problems as above, the table header area is not using the correct color schemes (for all areas except NONE). This is how the same app looks under Substance 5.2dev:

Finally, a sample application with trees under Substance 5.1 Nebula Brick Wall skin:

While it looks as expected, it’s only by looking at the skin definition that you can see it’s using wrong background colors for most of the areas – here is how it’s looking under Substance 5.2dev:

The development of the next 5.2 version of Substance (code-named Quebec) is wrapping up. You’re more than welcome to take the latest 5.2dev binary drops for a spin. The release candidate is planned for May 11, with the final release scheduled for May 25.

Google’s Java editions

April 18th, 2009

Following the announcement of Google App Engine for Java, it’s interesting to see how Sun and Google differ in their analysis of market trends. Traditionally, Sun has three main “versions” of Java:

  • Java Standard Edition (SE) for desktop applications
  • Java Enterprise Edition (EE) for server side
  • Java Mobile Edition (ME) for phones

With JavaFX, the new (and perhaps belatedly rediscovered) focus on client side market has three versions:

  • Desktop profile
  • Mobile profile
  • TV profile

with a common profile that aims to write an application once, and have it run on all three types of displays – and the history will tell how well that will be supported and used in practice.

What about Google? This is how i see it:

  • GWT is Java Web Edition (WE)
  • Android is Java Device Edition (DE)
  • App Engine is Java Cloud Edition (CE)

and no stated goal (at least yet) to provide a common edition for GWT and Android.