Substance look and feel - custom skinning


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:

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:

The second pattern is decorating. The decoration 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 decoration 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 decoration 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 fill 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 painted by the current fill 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 fill painter as well.