Substance skinning primer

November 6th, 2007

As Substance look-and-feel nears the official release 4.1 (scheduled for November 12th), i’m working on the missing documentation. This entry talks about the using the painter layer to skin custom components.

As mentioned in the painter overview, most of the Substance painting logic is abstracted into a set of painters. This not only allows preventing duplicate painting sequence in the Substance UI delegates. This also provides a painting layer for the applications that wish to paint custom components in a way that is consistent with other Substance visuals.

This applies in two major cases:

  • Providing consistent painting for a standalone component suite, such as SwingX.
  • Providing consistent painting for custom components and visual areas of a specific application.

Instead of trying to match the colors, gradients and animation sequences from the current Substance skin (which might change between various releases), applications can use the Substance painting APIs. This will result in code which is shorter, more maintainable and also produces consistent results.

Skinning primer

The following Substance APIs are most suited for painting custom components:

Most of the Substance UI delegates use a combination of the above APIs. While the exact combination in the existing UI delegates is subject to change in between releases, you can study the core Substance code to see the main combination patterns.

The first pattern is watermark overlaying. The watermarks are painted on most Swing containers, and on some components as well. In simpler cases (such as JPanel), the watermark is painted on top of the gradient fill. In more complex scenarios, after the watermark has been painted, the fill sequence is repeated with lower alpha value. Here is an example of such a scenario:

In this scenario, while the regular controls and containers on the content pane are painted with the regular watermark, the frame header (title pane and tool bar) has less “intrusive” watermark painting. This is achieved by the following sequence:

  • Using the header painter to paint the background gradient.
  • Using the watermark to paint the current watermark.
  • Using the header painter once again, this time with the AlphaComposite.SRC_OVER with alpha value of 0.5.

The second pattern is decorating. The header painters can be used to provide distinct painting to some containers, this setting them “apart” from the rest of the application. As the pattern name implies, this works best on specialized containers and visual areas that are situated along the window edges. Here is an example of SwingX JXLoginDialog component painted by the Substance SwingX plugin:

In this scenario, the JXLoginDialog has a “decoration” strip located along the top side of the window. To paint the background of this component, the custom UI delegate is using the current header painter, which results in a consistent appearance of the top portion of this dialog.Here is another example of this pattern, this time on the JXStatusBar component from SwingX component suite. Assuming that this component will be placed along the bottom side of the frame, the matching UI delegate in the Substance SwingX plugin uses the current header painter to provide a distinct appearance of status bar which is consistent with the title pane and menu bar:

The third pattern is border tracing. Those components that require consistent painting of borders or contours can use the border painter with the matching contour. Here is an example of border tracing in the JRibbon component from Flamingo component suite under the Substance Flamingo plugin:
This UI delegate uses the border painter extensively to create the required visuals. Note the outer contour of the ribbon that also includes the selected tab button, and the inner contours of the ribbon tasks.Here is another example of this pattern, this time on the JCommandButton component from Flamingo component suite. The custom UI delegate uses the border painter to paint the button border (a simpler contour in this case):

The last pattern is gradient filling. It is used to paint the inner fill of custom components (along with the border tracing pattern to paint the component contour). This pattern uses the gradient painter with the matching contour. Here is an example of the JRibbon component from Flamingo component suite:
In this example, the first toggle tab button (Write) is filled by the current gradient painter, providing a consistent appearance with the rest of the application controls. Another example is the previous screenshot (of the JCommandButton), where the button fill is painted by the current gradient painter as well.